/src/samba/lib/util/util.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Samba utility functions |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | Copyright (C) Jeremy Allison 2001-2002 |
6 | | Copyright (C) Simo Sorce 2001-2011 |
7 | | Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003. |
8 | | Copyright (C) James J Myers 2003 |
9 | | Copyright (C) Volker Lendecke 2010 |
10 | | Copyright (C) Swen Schillig 2019 |
11 | | |
12 | | This program is free software; you can redistribute it and/or modify |
13 | | it under the terms of the GNU General Public License as published by |
14 | | the Free Software Foundation; either version 3 of the License, or |
15 | | (at your option) any later version. |
16 | | |
17 | | This program is distributed in the hope that it will be useful, |
18 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | | GNU General Public License for more details. |
21 | | |
22 | | You should have received a copy of the GNU General Public License |
23 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | | */ |
25 | | |
26 | | #include "replace.h" |
27 | | #include <talloc.h> |
28 | | #include <tevent.h> |
29 | | #include "system/network.h" |
30 | | #include "system/filesys.h" |
31 | | #include "system/locale.h" |
32 | | #include "system/shmem.h" |
33 | | #include "system/passwd.h" |
34 | | #include "system/time.h" |
35 | | #include "system/wait.h" |
36 | | #include "debug.h" |
37 | | #include "samba_util.h" |
38 | | #include "lib/util/select.h" |
39 | | #include <libgen.h> |
40 | | #include <gnutls/gnutls.h> |
41 | | |
42 | | #ifdef HAVE_SYS_PRCTL_H |
43 | | #include <sys/prctl.h> |
44 | | #endif |
45 | | |
46 | | #undef malloc |
47 | | #undef strcasecmp |
48 | | #undef strncasecmp |
49 | | #undef strdup |
50 | | #undef realloc |
51 | | #undef calloc |
52 | | |
53 | | /** |
54 | | * @file |
55 | | * @brief Misc utility functions |
56 | | */ |
57 | | |
58 | | /** |
59 | | Find a suitable temporary directory. The result should be copied immediately |
60 | | as it may be overwritten by a subsequent call. |
61 | | **/ |
62 | | _PUBLIC_ const char *tmpdir(void) |
63 | 0 | { |
64 | 0 | char *p; |
65 | 0 | if ((p = getenv("TMPDIR"))) |
66 | 0 | return p; |
67 | 0 | return "/tmp"; |
68 | 0 | } |
69 | | |
70 | | |
71 | | /** |
72 | | Create a tmp file, open it and immediately unlink it. |
73 | | If dir is NULL uses tmpdir() |
74 | | Returns the file descriptor or -1 on error. |
75 | | **/ |
76 | | int create_unlink_tmp(const char *dir) |
77 | 0 | { |
78 | 0 | size_t len = strlen(dir ? dir : (dir = tmpdir())); |
79 | 0 | char fname[len+25]; |
80 | 0 | int fd; |
81 | 0 | mode_t mask; |
82 | |
|
83 | 0 | len = snprintf(fname, sizeof(fname), "%s/listenerlock_XXXXXX", dir); |
84 | 0 | if (len >= sizeof(fname)) { |
85 | 0 | errno = ENOMEM; |
86 | 0 | return -1; |
87 | 0 | } |
88 | 0 | mask = umask(S_IRWXO | S_IRWXG); |
89 | 0 | fd = mkstemp(fname); |
90 | 0 | umask(mask); |
91 | 0 | if (fd == -1) { |
92 | 0 | return -1; |
93 | 0 | } |
94 | 0 | if (unlink(fname) == -1) { |
95 | 0 | int sys_errno = errno; |
96 | 0 | close(fd); |
97 | 0 | errno = sys_errno; |
98 | 0 | return -1; |
99 | 0 | } |
100 | 0 | return fd; |
101 | 0 | } |
102 | | |
103 | | |
104 | | /** |
105 | | Check if a file exists - call vfs_file_exist for samba files. |
106 | | **/ |
107 | | _PUBLIC_ bool file_exist(const char *fname) |
108 | 0 | { |
109 | 0 | struct stat st; |
110 | |
|
111 | 0 | if (stat(fname, &st) != 0) { |
112 | 0 | return false; |
113 | 0 | } |
114 | | |
115 | 0 | return ((S_ISREG(st.st_mode)) || (S_ISFIFO(st.st_mode))); |
116 | 0 | } |
117 | | |
118 | | /** |
119 | | * @brief Return a files modification time. |
120 | | * |
121 | | * @param fname The name of the file. |
122 | | * |
123 | | * @param mt A pointer to store the modification time. |
124 | | * |
125 | | * @return 0 on success, errno otherwise. |
126 | | */ |
127 | | _PUBLIC_ int file_modtime(const char *fname, struct timespec *mt) |
128 | 0 | { |
129 | 0 | struct stat st = {0}; |
130 | |
|
131 | 0 | if (stat(fname, &st) != 0) { |
132 | 0 | return errno; |
133 | 0 | } |
134 | | |
135 | 0 | *mt = get_mtimespec(&st); |
136 | 0 | return 0; |
137 | 0 | } |
138 | | |
139 | | /** |
140 | | Check file permissions. |
141 | | **/ |
142 | | |
143 | | _PUBLIC_ bool file_check_permissions(const char *fname, |
144 | | uid_t uid, |
145 | | mode_t file_perms, |
146 | | struct stat *pst) |
147 | 0 | { |
148 | 0 | int ret; |
149 | 0 | struct stat st; |
150 | |
|
151 | 0 | if (pst == NULL) { |
152 | 0 | pst = &st; |
153 | 0 | } |
154 | |
|
155 | 0 | ZERO_STRUCTP(pst); |
156 | |
|
157 | 0 | ret = stat(fname, pst); |
158 | 0 | if (ret != 0) { |
159 | 0 | DEBUG(0, ("stat failed on file '%s': %s\n", |
160 | 0 | fname, strerror(errno))); |
161 | 0 | return false; |
162 | 0 | } |
163 | | |
164 | 0 | if (pst->st_uid != uid && !uid_wrapper_enabled()) { |
165 | 0 | DEBUG(0, ("invalid ownership of file '%s': " |
166 | 0 | "owned by uid %u, should be %u\n", |
167 | 0 | fname, (unsigned int)pst->st_uid, |
168 | 0 | (unsigned int)uid)); |
169 | 0 | return false; |
170 | 0 | } |
171 | | |
172 | 0 | if ((pst->st_mode & 0777) != file_perms) { |
173 | 0 | DEBUG(0, ("invalid permissions on file " |
174 | 0 | "'%s': has 0%o should be 0%o\n", fname, |
175 | 0 | (unsigned int)(pst->st_mode & 0777), |
176 | 0 | (unsigned int)file_perms)); |
177 | 0 | return false; |
178 | 0 | } |
179 | | |
180 | 0 | return true; |
181 | 0 | } |
182 | | |
183 | | /** |
184 | | Check if a directory exists. |
185 | | **/ |
186 | | |
187 | | _PUBLIC_ bool directory_exist(const char *dname) |
188 | 0 | { |
189 | 0 | struct stat st; |
190 | 0 | bool ret; |
191 | |
|
192 | 0 | if (stat(dname,&st) != 0) { |
193 | 0 | return false; |
194 | 0 | } |
195 | | |
196 | 0 | ret = S_ISDIR(st.st_mode); |
197 | 0 | if(!ret) |
198 | 0 | errno = ENOTDIR; |
199 | 0 | return ret; |
200 | 0 | } |
201 | | |
202 | | /** |
203 | | * Try to create the specified directory if it didn't exist. |
204 | | * A symlink to a directory is also accepted as a valid existing directory. |
205 | | * |
206 | | * @retval true if the directory already existed |
207 | | * or was successfully created. |
208 | | */ |
209 | | _PUBLIC_ bool directory_create_or_exist(const char *dname, |
210 | | mode_t dir_perms) |
211 | 0 | { |
212 | 0 | int ret; |
213 | 0 | mode_t old_umask; |
214 | | |
215 | | /* Create directory */ |
216 | 0 | old_umask = umask(0); |
217 | 0 | ret = mkdir(dname, dir_perms); |
218 | 0 | if (ret == -1 && errno != EEXIST) { |
219 | 0 | int dbg_level = geteuid() == 0 ? DBGLVL_ERR : DBGLVL_NOTICE; |
220 | |
|
221 | 0 | DBG_PREFIX(dbg_level, |
222 | 0 | ("mkdir failed on directory %s: %s\n", |
223 | 0 | dname, |
224 | 0 | strerror(errno))); |
225 | 0 | umask(old_umask); |
226 | 0 | return false; |
227 | 0 | } |
228 | 0 | umask(old_umask); |
229 | |
|
230 | 0 | if (ret != 0 && errno == EEXIST) { |
231 | 0 | struct stat sbuf; |
232 | |
|
233 | 0 | ret = lstat(dname, &sbuf); |
234 | 0 | if (ret != 0) { |
235 | 0 | return false; |
236 | 0 | } |
237 | | |
238 | 0 | if (S_ISDIR(sbuf.st_mode)) { |
239 | 0 | return true; |
240 | 0 | } |
241 | | |
242 | 0 | if (S_ISLNK(sbuf.st_mode)) { |
243 | 0 | ret = stat(dname, &sbuf); |
244 | 0 | if (ret != 0) { |
245 | 0 | return false; |
246 | 0 | } |
247 | | |
248 | 0 | if (S_ISDIR(sbuf.st_mode)) { |
249 | 0 | return true; |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | 0 | return false; |
254 | 0 | } |
255 | | |
256 | 0 | return true; |
257 | 0 | } |
258 | | |
259 | | _PUBLIC_ bool directory_create_or_exists_recursive( |
260 | | const char *dname, |
261 | | mode_t dir_perms) |
262 | 0 | { |
263 | 0 | bool ok; |
264 | |
|
265 | 0 | ok = directory_create_or_exist(dname, dir_perms); |
266 | 0 | if (!ok) { |
267 | 0 | if (!directory_exist(dname)) { |
268 | 0 | char tmp[PATH_MAX] = {0}; |
269 | 0 | char *parent = NULL; |
270 | 0 | size_t n; |
271 | | |
272 | | /* Use the null context */ |
273 | 0 | n = strlcpy(tmp, dname, sizeof(tmp)); |
274 | 0 | if (n < strlen(dname)) { |
275 | 0 | DBG_ERR("Path too long!\n"); |
276 | 0 | return false; |
277 | 0 | } |
278 | | |
279 | 0 | parent = dirname(tmp); |
280 | 0 | if (parent == NULL) { |
281 | 0 | DBG_ERR("Failed to create dirname!\n"); |
282 | 0 | return false; |
283 | 0 | } |
284 | | |
285 | 0 | ok = directory_create_or_exists_recursive(parent, |
286 | 0 | dir_perms); |
287 | 0 | if (!ok) { |
288 | 0 | return false; |
289 | 0 | } |
290 | | |
291 | 0 | ok = directory_create_or_exist(dname, dir_perms); |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | 0 | return ok; |
296 | 0 | } |
297 | | |
298 | | /** |
299 | | * @brief Try to create a specified directory if it doesn't exist. |
300 | | * |
301 | | * The function creates a directory with the given uid and permissions if it |
302 | | * doesn't exist. If it exists it makes sure the uid and permissions are |
303 | | * correct and it will fail if they are different. |
304 | | * |
305 | | * @param[in] dname The directory to create. |
306 | | * |
307 | | * @param[in] uid The uid the directory needs to belong too. |
308 | | * |
309 | | * @param[in] dir_perms The expected permissions of the directory. |
310 | | * |
311 | | * @return True on success, false on error. |
312 | | */ |
313 | | _PUBLIC_ bool directory_create_or_exist_strict(const char *dname, |
314 | | uid_t uid, |
315 | | mode_t dir_perms) |
316 | 0 | { |
317 | 0 | struct stat st; |
318 | 0 | bool ok; |
319 | 0 | int rc; |
320 | |
|
321 | 0 | ok = directory_create_or_exist(dname, dir_perms); |
322 | 0 | if (!ok) { |
323 | 0 | return false; |
324 | 0 | } |
325 | | |
326 | 0 | rc = lstat(dname, &st); |
327 | 0 | if (rc == -1) { |
328 | 0 | DEBUG(0, ("lstat failed on created directory %s: %s\n", |
329 | 0 | dname, strerror(errno))); |
330 | 0 | return false; |
331 | 0 | } |
332 | | |
333 | | /* Check ownership and permission on existing directory */ |
334 | 0 | if (!S_ISDIR(st.st_mode)) { |
335 | 0 | DEBUG(0, ("directory %s isn't a directory\n", |
336 | 0 | dname)); |
337 | 0 | return false; |
338 | 0 | } |
339 | 0 | if (st.st_uid != uid && !uid_wrapper_enabled()) { |
340 | 0 | DBG_NOTICE("invalid ownership on directory " |
341 | 0 | "%s\n", dname); |
342 | 0 | return false; |
343 | 0 | } |
344 | 0 | if ((st.st_mode & 0777) != dir_perms) { |
345 | 0 | DEBUG(0, ("invalid permissions on directory " |
346 | 0 | "'%s': has 0%o should be 0%o\n", dname, |
347 | 0 | (unsigned int)(st.st_mode & 0777), (unsigned int)dir_perms)); |
348 | 0 | return false; |
349 | 0 | } |
350 | | |
351 | 0 | return true; |
352 | 0 | } |
353 | | |
354 | | |
355 | | /** |
356 | | Sleep for a specified number of milliseconds. |
357 | | **/ |
358 | | |
359 | | _PUBLIC_ void smb_msleep(unsigned int t) |
360 | 0 | { |
361 | 0 | sys_poll_intr(NULL, 0, t); |
362 | 0 | } |
363 | | |
364 | | /** |
365 | | Get my own name, return in talloc'ed storage. |
366 | | **/ |
367 | | |
368 | | _PUBLIC_ char *get_myname(TALLOC_CTX *ctx) |
369 | 0 | { |
370 | 0 | char *p; |
371 | 0 | char hostname[HOST_NAME_MAX]; |
372 | | |
373 | | /* get my host name */ |
374 | 0 | if (gethostname(hostname, sizeof(hostname)) == -1) { |
375 | 0 | DEBUG(0,("gethostname failed\n")); |
376 | 0 | return NULL; |
377 | 0 | } |
378 | | |
379 | | /* Ensure null termination. */ |
380 | 0 | hostname[sizeof(hostname)-1] = '\0'; |
381 | | |
382 | | /* split off any parts after an initial . */ |
383 | 0 | p = strchr_m(hostname, '.'); |
384 | 0 | if (p) { |
385 | 0 | *p = 0; |
386 | 0 | } |
387 | |
|
388 | 0 | return talloc_strdup(ctx, hostname); |
389 | 0 | } |
390 | | |
391 | | /** |
392 | | Check if a process exists. Does this work on all unixes? |
393 | | **/ |
394 | | |
395 | | _PUBLIC_ bool process_exists_by_pid(pid_t pid) |
396 | 0 | { |
397 | | /* Doing kill with a non-positive pid causes messages to be |
398 | | * sent to places we don't want. */ |
399 | 0 | if (pid <= 0) { |
400 | 0 | return false; |
401 | 0 | } |
402 | 0 | return(kill(pid,0) == 0 || errno != ESRCH); |
403 | 0 | } |
404 | | |
405 | | /** |
406 | | Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping |
407 | | is dealt with in posix.c |
408 | | **/ |
409 | | |
410 | | _PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type) |
411 | 0 | { |
412 | 0 | struct flock lock; |
413 | 0 | int ret; |
414 | |
|
415 | 0 | DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type)); |
416 | |
|
417 | 0 | lock.l_type = type; |
418 | 0 | lock.l_whence = SEEK_SET; |
419 | 0 | lock.l_start = offset; |
420 | 0 | lock.l_len = count; |
421 | 0 | lock.l_pid = 0; |
422 | |
|
423 | 0 | ret = fcntl(fd,op,&lock); |
424 | |
|
425 | 0 | if (ret == -1 && errno != 0) |
426 | 0 | DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); |
427 | | |
428 | | /* a lock query */ |
429 | 0 | if (op == F_GETLK) { |
430 | 0 | if ((ret != -1) && |
431 | 0 | (lock.l_type != F_UNLCK) && |
432 | 0 | (lock.l_pid != 0) && |
433 | 0 | (lock.l_pid != tevent_cached_getpid())) { |
434 | 0 | DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid)); |
435 | 0 | return true; |
436 | 0 | } |
437 | | |
438 | | /* it must be not locked or locked by me */ |
439 | 0 | return false; |
440 | 0 | } |
441 | | |
442 | | /* a lock set or unset */ |
443 | 0 | if (ret == -1) { |
444 | 0 | DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n", |
445 | 0 | (double)offset,(double)count,op,type,strerror(errno))); |
446 | 0 | return false; |
447 | 0 | } |
448 | | |
449 | | /* everything went OK */ |
450 | 0 | DEBUG(8,("fcntl_lock: Lock call successful\n")); |
451 | |
|
452 | 0 | return true; |
453 | 0 | } |
454 | | |
455 | | struct debug_channel_level { |
456 | | int channel; |
457 | | int level; |
458 | | }; |
459 | | |
460 | | static void debugadd_channel_cb(const char *buf, void *private_data) |
461 | 0 | { |
462 | 0 | struct debug_channel_level *dcl = |
463 | 0 | (struct debug_channel_level *)private_data; |
464 | |
|
465 | 0 | DEBUGADDC(dcl->channel, dcl->level,("%s", buf)); |
466 | 0 | } |
467 | | |
468 | | static void debugadd_cb(const char *buf, void *private_data) |
469 | 6.86M | { |
470 | 6.86M | int *plevel = (int *)private_data; |
471 | 6.86M | DEBUGADD(*plevel, ("%s", buf)); |
472 | 6.86M | } |
473 | | |
474 | | void print_asc_cb(const uint8_t *buf, int len, |
475 | | void (*cb)(const char *buf, void *private_data), |
476 | | void *private_data) |
477 | 507M | { |
478 | 507M | int i; |
479 | 507M | char s[2]; |
480 | 507M | s[1] = 0; |
481 | | |
482 | 1.02G | for (i=0; i<len; i++) { |
483 | 512M | s[0] = isprint(buf[i]) ? buf[i] : '.'; |
484 | 512M | cb(s, private_data); |
485 | 512M | } |
486 | 507M | } |
487 | | |
488 | | void print_asc(int level, const uint8_t *buf,int len) |
489 | 1.57M | { |
490 | 1.57M | print_asc_cb(buf, len, debugadd_cb, &level); |
491 | 1.57M | } |
492 | | |
493 | | static void dump_data_block16(const char *prefix, size_t idx, |
494 | | const uint8_t *buf, size_t len, |
495 | | void (*cb)(const char *buf, void *private_data), |
496 | | void *private_data) |
497 | 32.2M | { |
498 | 32.2M | size_t prefix_len = strlen(prefix); |
499 | | /* 16 (=%04zX) + 2 (=[]) + 1 (='\0') => 19 */ |
500 | 32.2M | char tmp[prefix_len + 19]; |
501 | 32.2M | size_t i; |
502 | | |
503 | 32.2M | SMB_ASSERT(len <= 16); |
504 | | |
505 | 32.2M | snprintf(tmp, sizeof(tmp), "%s[%04zX]", prefix, idx); |
506 | 32.2M | cb(tmp, private_data); |
507 | | |
508 | 548M | for (i=0; i<16; i++) { |
509 | 516M | if (i == 8) { |
510 | 32.2M | cb(" ", private_data); |
511 | 32.2M | } |
512 | 516M | if (i < len) { |
513 | 506M | snprintf(tmp, sizeof(tmp), " %02X", (int)buf[i]); |
514 | 506M | } else { |
515 | 10.5M | snprintf(tmp, sizeof(tmp), " "); |
516 | 10.5M | } |
517 | 516M | cb(tmp, private_data); |
518 | 516M | } |
519 | | |
520 | 32.2M | cb(" ", private_data); |
521 | | |
522 | 32.2M | if (len == 0) { |
523 | 0 | cb("EMPTY BLOCK\n", private_data); |
524 | 0 | return; |
525 | 0 | } |
526 | | |
527 | 538M | for (i=0; i<len; i++) { |
528 | 506M | if (i == 8) { |
529 | 31.5M | cb(" ", private_data); |
530 | 31.5M | } |
531 | 506M | print_asc_cb(&buf[i], 1, cb, private_data); |
532 | 506M | } |
533 | | |
534 | 32.2M | cb("\n", private_data); |
535 | 32.2M | } |
536 | | |
537 | | /** |
538 | | * Write dump of binary data to a callback |
539 | | */ |
540 | | void dump_data_cb(const uint8_t *buf, int len, |
541 | | bool omit_zero_bytes, |
542 | | void (*cb)(const char *buf, void *private_data), |
543 | | void *private_data) |
544 | 900k | { |
545 | 900k | int i=0; |
546 | 900k | bool skipped = false; |
547 | | |
548 | 900k | if (len<=0) return; |
549 | | |
550 | 73.3M | for (i=0;i<len;i+=16) { |
551 | 72.4M | size_t remaining_len = len - i; |
552 | 72.4M | size_t this_len = MIN(remaining_len, 16); |
553 | 72.4M | const uint8_t *this_buf = &buf[i]; |
554 | | |
555 | 72.4M | if (omit_zero_bytes && (i > 0) && (remaining_len > 16) && |
556 | 71.3M | (this_len == 16) && all_zero(this_buf, 16)) |
557 | 40.1M | { |
558 | 40.1M | if (!skipped) { |
559 | 1.20M | cb("skipping zero buffer bytes\n", |
560 | 1.20M | private_data); |
561 | 1.20M | skipped = true; |
562 | 1.20M | } |
563 | 40.1M | continue; |
564 | 40.1M | } |
565 | | |
566 | 32.2M | skipped = false; |
567 | 32.2M | dump_data_block16("", i, this_buf, this_len, |
568 | 32.2M | cb, private_data); |
569 | 32.2M | } |
570 | 900k | } |
571 | | |
572 | | /** |
573 | | * Write dump of binary data to the log file. |
574 | | * |
575 | | * The data is only written if the log level is at least level. |
576 | | */ |
577 | | _PUBLIC_ void dump_data(int level, const uint8_t *buf, int len) |
578 | 0 | { |
579 | 0 | if (!DEBUGLVL(level)) { |
580 | 0 | return; |
581 | 0 | } |
582 | 0 | dump_data_cb(buf, len, false, debugadd_cb, &level); |
583 | 0 | } |
584 | | |
585 | | /** |
586 | | * Write dump of binary data to the log file. |
587 | | * |
588 | | * The data is only written if the log level is at least level for |
589 | | * debug class dbgc_class. |
590 | | */ |
591 | | _PUBLIC_ void dump_data_dbgc(int dbgc_class, int level, const uint8_t *buf, int len) |
592 | 0 | { |
593 | 0 | struct debug_channel_level dcl = { dbgc_class, level }; |
594 | |
|
595 | 0 | if (!DEBUGLVLC(dbgc_class, level)) { |
596 | 0 | return; |
597 | 0 | } |
598 | 0 | dump_data_cb(buf, len, false, debugadd_channel_cb, &dcl); |
599 | 0 | } |
600 | | |
601 | | /** |
602 | | * Write dump of binary data to the log file. |
603 | | * |
604 | | * The data is only written if the log level is at least level. |
605 | | * 16 zero bytes in a row are omitted |
606 | | */ |
607 | | _PUBLIC_ void dump_data_skip_zeros(int level, const uint8_t *buf, int len) |
608 | 0 | { |
609 | 0 | if (!DEBUGLVL(level)) { |
610 | 0 | return; |
611 | 0 | } |
612 | 0 | dump_data_cb(buf, len, true, debugadd_cb, &level); |
613 | 0 | } |
614 | | |
615 | | static void fprintf_cb(const char *buf, void *private_data) |
616 | 0 | { |
617 | 0 | FILE *f = (FILE *)private_data; |
618 | 0 | fprintf(f, "%s", buf); |
619 | 0 | } |
620 | | |
621 | | void dump_data_file(const uint8_t *buf, int len, bool omit_zero_bytes, |
622 | | FILE *f) |
623 | 0 | { |
624 | 0 | dump_data_cb(buf, len, omit_zero_bytes, fprintf_cb, f); |
625 | 0 | } |
626 | | |
627 | | /** |
628 | | * Write dump of compared binary data to a callback |
629 | | */ |
630 | | void dump_data_diff_cb(const uint8_t *buf1, size_t len1, |
631 | | const uint8_t *buf2, size_t len2, |
632 | | bool omit_zero_bytes, |
633 | | void (*cb)(const char *buf, void *private_data), |
634 | | void *private_data) |
635 | 0 | { |
636 | 0 | size_t len = MAX(len1, len2); |
637 | 0 | size_t i; |
638 | 0 | bool skipped = false; |
639 | |
|
640 | 0 | for (i=0; i<len; i+=16) { |
641 | 0 | size_t remaining_len = len - i; |
642 | 0 | size_t remaining_len1 = 0; |
643 | 0 | size_t this_len1 = 0; |
644 | 0 | const uint8_t *this_buf1 = NULL; |
645 | 0 | size_t remaining_len2 = 0; |
646 | 0 | size_t this_len2 = 0; |
647 | 0 | const uint8_t *this_buf2 = NULL; |
648 | |
|
649 | 0 | if (i < len1) { |
650 | 0 | remaining_len1 = len1 - i; |
651 | 0 | this_len1 = MIN(remaining_len1, 16); |
652 | 0 | this_buf1 = &buf1[i]; |
653 | 0 | } |
654 | 0 | if (i < len2) { |
655 | 0 | remaining_len2 = len2 - i; |
656 | 0 | this_len2 = MIN(remaining_len2, 16); |
657 | 0 | this_buf2 = &buf2[i]; |
658 | 0 | } |
659 | |
|
660 | 0 | if (omit_zero_bytes && (i > 0) && (remaining_len > 16) && |
661 | 0 | (this_len1 == 16) && all_zero(this_buf1, 16) && |
662 | 0 | (this_len2 == 16) && all_zero(this_buf2, 16)) |
663 | 0 | { |
664 | 0 | if (!skipped) { |
665 | 0 | cb("skipping zero buffer bytes\n", |
666 | 0 | private_data); |
667 | 0 | skipped = true; |
668 | 0 | } |
669 | 0 | continue; |
670 | 0 | } |
671 | | |
672 | 0 | skipped = false; |
673 | |
|
674 | 0 | if ((this_len1 == this_len2) && |
675 | 0 | (memcmp(this_buf1, this_buf2, this_len1) == 0)) |
676 | 0 | { |
677 | 0 | dump_data_block16(" ", i, this_buf1, this_len1, |
678 | 0 | cb, private_data); |
679 | 0 | continue; |
680 | 0 | } |
681 | | |
682 | 0 | dump_data_block16("-", i, this_buf1, this_len1, |
683 | 0 | cb, private_data); |
684 | 0 | dump_data_block16("+", i, this_buf2, this_len2, |
685 | 0 | cb, private_data); |
686 | 0 | } |
687 | 0 | } |
688 | | |
689 | | _PUBLIC_ void dump_data_diff(int dbgc_class, int level, |
690 | | bool omit_zero_bytes, |
691 | | const uint8_t *buf1, size_t len1, |
692 | | const uint8_t *buf2, size_t len2) |
693 | 0 | { |
694 | 0 | struct debug_channel_level dcl = { dbgc_class, level }; |
695 | |
|
696 | 0 | if (!DEBUGLVLC(dbgc_class, level)) { |
697 | 0 | return; |
698 | 0 | } |
699 | 0 | dump_data_diff_cb(buf1, |
700 | 0 | len1, |
701 | 0 | buf2, |
702 | 0 | len2, |
703 | 0 | omit_zero_bytes, |
704 | 0 | debugadd_channel_cb, |
705 | 0 | &dcl); |
706 | 0 | } |
707 | | |
708 | | _PUBLIC_ void dump_data_file_diff(FILE *f, |
709 | | bool omit_zero_bytes, |
710 | | const uint8_t *buf1, size_t len1, |
711 | | const uint8_t *buf2, size_t len2) |
712 | 0 | { |
713 | 0 | dump_data_diff_cb(buf1, len1, buf2, len2, omit_zero_bytes, fprintf_cb, f); |
714 | 0 | } |
715 | | |
716 | | /** |
717 | | malloc that aborts with smb_panic on fail or zero size. |
718 | | **/ |
719 | | |
720 | | _PUBLIC_ void *smb_xmalloc(size_t size) |
721 | 0 | { |
722 | 0 | void *p; |
723 | 0 | if (size == 0) |
724 | 0 | smb_panic("smb_xmalloc: called with zero size.\n"); |
725 | 0 | if ((p = malloc(size)) == NULL) |
726 | 0 | smb_panic("smb_xmalloc: malloc fail.\n"); |
727 | 0 | return p; |
728 | 0 | } |
729 | | |
730 | | /** |
731 | | Memdup with smb_panic on fail. |
732 | | **/ |
733 | | |
734 | | _PUBLIC_ void *smb_xmemdup(const void *p, size_t size) |
735 | 0 | { |
736 | 0 | void *p2; |
737 | 0 | p2 = smb_xmalloc(size); |
738 | 0 | memcpy(p2, p, size); |
739 | 0 | return p2; |
740 | 0 | } |
741 | | |
742 | | /** |
743 | | strdup that aborts on malloc fail. |
744 | | **/ |
745 | | |
746 | | char *smb_xstrdup(const char *s) |
747 | 105 | { |
748 | | #if defined(PARANOID_MALLOC_CHECKER) |
749 | | #ifdef strdup |
750 | | #undef strdup |
751 | | #endif |
752 | | #endif |
753 | | |
754 | | #ifndef HAVE_STRDUP |
755 | | #define strdup rep_strdup |
756 | | #endif |
757 | | |
758 | 105 | char *s1 = strdup(s); |
759 | | #if defined(PARANOID_MALLOC_CHECKER) |
760 | | #ifdef strdup |
761 | | #undef strdup |
762 | | #endif |
763 | | #define strdup(s) __ERROR_DONT_USE_STRDUP_DIRECTLY |
764 | | #endif |
765 | 105 | if (!s1) { |
766 | 0 | smb_panic("smb_xstrdup: malloc failed"); |
767 | 0 | } |
768 | 105 | return s1; |
769 | | |
770 | 105 | } |
771 | | |
772 | | /** |
773 | | strndup that aborts on malloc fail. |
774 | | **/ |
775 | | |
776 | | char *smb_xstrndup(const char *s, size_t n) |
777 | 0 | { |
778 | | #if defined(PARANOID_MALLOC_CHECKER) |
779 | | #ifdef strndup |
780 | | #undef strndup |
781 | | #endif |
782 | | #endif |
783 | |
|
784 | | #if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP)) |
785 | | #undef HAVE_STRNDUP |
786 | | #define strndup rep_strndup |
787 | | #endif |
788 | |
|
789 | 0 | char *s1 = strndup(s, n); |
790 | | #if defined(PARANOID_MALLOC_CHECKER) |
791 | | #ifdef strndup |
792 | | #undef strndup |
793 | | #endif |
794 | | #define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY |
795 | | #endif |
796 | 0 | if (!s1) { |
797 | 0 | smb_panic("smb_xstrndup: malloc failed"); |
798 | 0 | } |
799 | 0 | return s1; |
800 | 0 | } |
801 | | |
802 | | |
803 | | |
804 | | /** |
805 | | Like strdup but for memory. |
806 | | **/ |
807 | | |
808 | | _PUBLIC_ void *smb_memdup(const void *p, size_t size) |
809 | 0 | { |
810 | 0 | void *p2; |
811 | 0 | if (size == 0) |
812 | 0 | return NULL; |
813 | 0 | p2 = malloc(size); |
814 | 0 | if (!p2) |
815 | 0 | return NULL; |
816 | 0 | memcpy(p2, p, size); |
817 | 0 | return p2; |
818 | 0 | } |
819 | | |
820 | | /** |
821 | | * Write a password to the log file. |
822 | | * |
823 | | * @note Only actually does something if DEBUG_PASSWORD was defined during |
824 | | * compile-time. |
825 | | */ |
826 | | _PUBLIC_ void dump_data_pw(const char *msg, const uint8_t * data, size_t len) |
827 | 0 | { |
828 | 0 | #ifdef DEBUG_PASSWORD |
829 | 0 | DEBUG(11, ("%s", msg)); |
830 | 0 | if (data != NULL && len > 0) |
831 | 0 | { |
832 | 0 | dump_data(11, data, len); |
833 | 0 | } |
834 | 0 | #endif |
835 | 0 | } |
836 | | |
837 | | static void dump_data_addbuf_cb(const char *buf, void *private_data) |
838 | 0 | { |
839 | 0 | char **str = private_data; |
840 | 0 | talloc_asprintf_addbuf(str, "%s", buf); |
841 | 0 | } |
842 | | |
843 | | _PUBLIC_ void dump_data_addbuf(const uint8_t *buf, size_t buflen, char **str) |
844 | 0 | { |
845 | 0 | dump_data_cb(buf, buflen, false, dump_data_addbuf_cb, str); |
846 | 0 | } |
847 | | |
848 | | |
849 | | /** |
850 | | * see if a range of memory is all zero. A NULL pointer is considered |
851 | | * to be all zero |
852 | | */ |
853 | | _PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size) |
854 | 71.6M | { |
855 | 71.6M | size_t i; |
856 | 71.6M | if (!ptr) return true; |
857 | 770M | for (i=0;i<size;i++) { |
858 | 729M | if (ptr[i]) return false; |
859 | 729M | } |
860 | 40.3M | return true; |
861 | 71.6M | } |
862 | | |
863 | | /** |
864 | | realloc an array, checking for integer overflow in the array size |
865 | | */ |
866 | | _PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail) |
867 | 635 | { |
868 | 755 | #define MAX_MALLOC_SIZE 0x7fffffff |
869 | 635 | if (count == 0 || |
870 | 635 | count >= MAX_MALLOC_SIZE/el_size) { |
871 | 0 | if (free_on_fail) |
872 | 0 | SAFE_FREE(ptr); |
873 | 0 | return NULL; |
874 | 0 | } |
875 | 635 | if (!ptr) { |
876 | 635 | return malloc(el_size * count); |
877 | 635 | } |
878 | 0 | return realloc(ptr, el_size * count); |
879 | 635 | } |
880 | | |
881 | | /**************************************************************************** |
882 | | Type-safe malloc. |
883 | | ****************************************************************************/ |
884 | | |
885 | | void *malloc_array(size_t el_size, unsigned int count) |
886 | 635 | { |
887 | 635 | return realloc_array(NULL, el_size, count, false); |
888 | 635 | } |
889 | | |
890 | | /**************************************************************************** |
891 | | Type-safe memalign |
892 | | ****************************************************************************/ |
893 | | |
894 | | void *memalign_array(size_t el_size, size_t align, unsigned int count) |
895 | 0 | { |
896 | 0 | if (el_size == 0 || count >= MAX_MALLOC_SIZE/el_size) { |
897 | 0 | return NULL; |
898 | 0 | } |
899 | | |
900 | 0 | return memalign(align, el_size*count); |
901 | 0 | } |
902 | | |
903 | | /**************************************************************************** |
904 | | Type-safe calloc. |
905 | | ****************************************************************************/ |
906 | | |
907 | | void *calloc_array(size_t size, size_t nmemb) |
908 | 120 | { |
909 | 120 | if (nmemb >= MAX_MALLOC_SIZE/size) { |
910 | 0 | return NULL; |
911 | 0 | } |
912 | 120 | if (size == 0 || nmemb == 0) { |
913 | 0 | return NULL; |
914 | 0 | } |
915 | 120 | return calloc(nmemb, size); |
916 | 120 | } |
917 | | |
918 | | /** |
919 | | Trim the specified elements off the front and back of a string. |
920 | | **/ |
921 | | _PUBLIC_ bool trim_string(char *s, const char *front, const char *back) |
922 | 17.5k | { |
923 | 17.5k | bool ret = false; |
924 | 17.5k | size_t front_len; |
925 | 17.5k | size_t back_len; |
926 | 17.5k | size_t len; |
927 | | |
928 | | /* Ignore null or empty strings. */ |
929 | 17.5k | if (!s || (s[0] == '\0')) { |
930 | 792 | return false; |
931 | 792 | } |
932 | 16.7k | len = strlen(s); |
933 | | |
934 | 16.7k | front_len = front? strlen(front) : 0; |
935 | 16.7k | back_len = back? strlen(back) : 0; |
936 | | |
937 | 16.7k | if (front_len) { |
938 | 0 | size_t front_trim = 0; |
939 | |
|
940 | 0 | while (strncmp(s+front_trim, front, front_len)==0) { |
941 | 0 | front_trim += front_len; |
942 | 0 | } |
943 | 0 | if (front_trim > 0) { |
944 | | /* Must use memmove here as src & dest can |
945 | | * easily overlap. Found by valgrind. JRA. */ |
946 | 0 | memmove(s, s+front_trim, (len-front_trim)+1); |
947 | 0 | len -= front_trim; |
948 | 0 | ret=true; |
949 | 0 | } |
950 | 0 | } |
951 | | |
952 | 16.7k | if (back_len) { |
953 | 17.6k | while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) { |
954 | 825 | s[len-back_len]='\0'; |
955 | 825 | len -= back_len; |
956 | 825 | ret=true; |
957 | 825 | } |
958 | 16.7k | } |
959 | 16.7k | return ret; |
960 | 17.5k | } |
961 | | |
962 | | /** |
963 | | Find the number of 'c' chars in a string |
964 | | **/ |
965 | | _PUBLIC_ _PURE_ size_t count_chars(const char *s, char c) |
966 | 0 | { |
967 | 0 | size_t count = 0; |
968 | |
|
969 | 0 | while (*s) { |
970 | 0 | if (*s == c) count++; |
971 | 0 | s ++; |
972 | 0 | } |
973 | |
|
974 | 0 | return count; |
975 | 0 | } |
976 | | |
977 | | /** |
978 | | * Routine to get hex characters and turn them into a byte array. |
979 | | * the array can be variable length. |
980 | | * - "0xnn" or "0Xnn" is specially catered for. |
981 | | * - The first non-hex-digit character (apart from possibly leading "0x" |
982 | | * finishes the conversion and skips the rest of the input. |
983 | | * - A single hex-digit character at the end of the string is skipped. |
984 | | * |
985 | | * valid examples: "0A5D15"; "0x123456" |
986 | | */ |
987 | | _PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len) |
988 | 0 | { |
989 | 0 | size_t i = 0; |
990 | 0 | size_t num_chars = 0; |
991 | | |
992 | | /* skip leading 0x prefix */ |
993 | 0 | if (strncasecmp(strhex, "0x", 2) == 0) { |
994 | 0 | i += 2; /* skip two chars */ |
995 | 0 | } |
996 | |
|
997 | 0 | while ((i < strhex_len) && (num_chars < p_len)) { |
998 | 0 | bool ok = hex_byte(&strhex[i], (uint8_t *)&p[num_chars]); |
999 | 0 | if (!ok) { |
1000 | 0 | break; |
1001 | 0 | } |
1002 | 0 | i += 2; |
1003 | 0 | num_chars += 1; |
1004 | 0 | } |
1005 | |
|
1006 | 0 | return num_chars; |
1007 | 0 | } |
1008 | | |
1009 | | /** |
1010 | | * Parse a hex string and return a data blob. |
1011 | | */ |
1012 | | _PUBLIC_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) |
1013 | 0 | { |
1014 | 0 | DATA_BLOB ret_blob = data_blob_talloc(mem_ctx, NULL, strlen(strhex)/2+1); |
1015 | 0 | if (ret_blob.data == NULL) { |
1016 | | /* ret_blob.length is already 0 */ |
1017 | 0 | return ret_blob; |
1018 | 0 | } |
1019 | 0 | ret_blob.length = strhex_to_str((char *)ret_blob.data, ret_blob.length, |
1020 | 0 | strhex, |
1021 | 0 | strlen(strhex)); |
1022 | |
|
1023 | 0 | return ret_blob; |
1024 | 0 | } |
1025 | | |
1026 | | /** |
1027 | | * Parse a hex dump and return a data blob. Hex dump is structured as |
1028 | | * is generated from dump_data_cb() elsewhere in this file |
1029 | | * |
1030 | | */ |
1031 | | _PUBLIC_ DATA_BLOB hexdump_to_data_blob(TALLOC_CTX *mem_ctx, const char *hexdump, size_t hexdump_len) |
1032 | 0 | { |
1033 | 0 | DATA_BLOB ret_blob = { 0 }; |
1034 | 0 | size_t i = 0; |
1035 | 0 | size_t char_count = 0; |
1036 | | /* hexdump line length is 77 chars long. We then use the ASCII representation of the bytes |
1037 | | * at the end of the final line to calculate how many are in that line, minus the extra space |
1038 | | * and newline. */ |
1039 | 0 | size_t hexdump_byte_count = (16 * (hexdump_len / 77)); |
1040 | 0 | if (hexdump_len % 77) { |
1041 | 0 | hexdump_byte_count += ((hexdump_len % 77) - 59 - 2); |
1042 | 0 | } |
1043 | |
|
1044 | 0 | ret_blob = data_blob_talloc(mem_ctx, NULL, hexdump_byte_count+1); |
1045 | 0 | for (; i+1 < hexdump_len && hexdump[i] != 0 && hexdump[i+1] != 0; i++) { |
1046 | 0 | if ((i%77) == 0) |
1047 | 0 | i += 7; /* Skip the offset at the start of the line */ |
1048 | 0 | if ((i%77) < 56) { /* position 56 is after both hex chunks */ |
1049 | 0 | if (hexdump[i] != ' ') { |
1050 | 0 | char_count += strhex_to_str((char *)&ret_blob.data[char_count], |
1051 | 0 | hexdump_byte_count - char_count, |
1052 | 0 | &hexdump[i], 2); |
1053 | 0 | i += 2; |
1054 | 0 | } else { |
1055 | 0 | i++; |
1056 | 0 | } |
1057 | 0 | } else { |
1058 | 0 | i++; |
1059 | 0 | } |
1060 | 0 | } |
1061 | 0 | ret_blob.length = char_count; |
1062 | |
|
1063 | 0 | return ret_blob; |
1064 | 0 | } |
1065 | | |
1066 | | /** |
1067 | | * Print a buf in hex. Assumes dst is at least (srclen*2)+1 large. |
1068 | | */ |
1069 | | _PUBLIC_ void hex_encode_buf(char *dst, const uint8_t *src, size_t srclen) |
1070 | 9.21k | { |
1071 | 9.21k | size_t i; |
1072 | 201k | for (i=0; i<srclen; i++) { |
1073 | 192k | snprintf(dst + i*2, 3, "%02X", src[i]); |
1074 | 192k | } |
1075 | | /* |
1076 | | * Ensure 0-termination for 0-length buffers |
1077 | | */ |
1078 | 9.21k | dst[srclen*2] = '\0'; |
1079 | 9.21k | } |
1080 | | |
1081 | | /** |
1082 | | * talloc version of hex_encode_buf() |
1083 | | */ |
1084 | | _PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len) |
1085 | 9.21k | { |
1086 | 9.21k | char *hex_buffer; |
1087 | | |
1088 | 9.21k | hex_buffer = talloc_array(mem_ctx, char, (len*2)+1); |
1089 | 9.21k | if (!hex_buffer) { |
1090 | 0 | return NULL; |
1091 | 0 | } |
1092 | 9.21k | hex_encode_buf(hex_buffer, buff_in, len); |
1093 | 9.21k | talloc_set_name_const(hex_buffer, hex_buffer); |
1094 | 9.21k | return hex_buffer; |
1095 | 9.21k | } |
1096 | | |
1097 | | /** |
1098 | | variant of strcmp() that handles NULL ptrs |
1099 | | **/ |
1100 | | _PUBLIC_ int strcmp_safe(const char *s1, const char *s2) |
1101 | 0 | { |
1102 | 0 | if (s1 == s2) { |
1103 | 0 | return 0; |
1104 | 0 | } |
1105 | 0 | if (s1 == NULL || s2 == NULL) { |
1106 | 0 | return s1?-1:1; |
1107 | 0 | } |
1108 | 0 | return strcmp(s1, s2); |
1109 | 0 | } |
1110 | | |
1111 | | |
1112 | | /** |
1113 | | return the number of bytes occupied by a buffer in ASCII format |
1114 | | the result includes the null termination |
1115 | | limited by 'n' bytes |
1116 | | **/ |
1117 | | _PUBLIC_ size_t ascii_len_n(const char *src, size_t n) |
1118 | 9.37M | { |
1119 | 9.37M | size_t len; |
1120 | | |
1121 | 9.37M | len = strnlen(src, n); |
1122 | 9.37M | if (len+1 <= n) { |
1123 | 9.32M | len += 1; |
1124 | 9.32M | } |
1125 | | |
1126 | 9.37M | return len; |
1127 | 9.37M | } |
1128 | | |
1129 | | _PUBLIC_ bool mem_equal_const_time(const void *s1, const void *s2, size_t n) |
1130 | 0 | { |
1131 | | /* Ensure we won't overflow the unsigned index used by gnutls. */ |
1132 | 0 | SMB_ASSERT(n <= UINT_MAX); |
1133 | | |
1134 | 0 | return gnutls_memcmp(s1, s2, n) == 0; |
1135 | 0 | } |
1136 | | |
1137 | | struct anonymous_shared_header { |
1138 | | union { |
1139 | | size_t length; |
1140 | | uint8_t pad[16]; |
1141 | | } u; |
1142 | | }; |
1143 | | |
1144 | | /* Map a shared memory buffer of at least nelem counters. */ |
1145 | | void *anonymous_shared_allocate(size_t orig_bufsz) |
1146 | 0 | { |
1147 | 0 | void *ptr; |
1148 | 0 | void *buf; |
1149 | 0 | size_t pagesz = getpagesize(); |
1150 | 0 | size_t pagecnt; |
1151 | 0 | size_t bufsz = orig_bufsz; |
1152 | 0 | struct anonymous_shared_header *hdr; |
1153 | |
|
1154 | 0 | bufsz += sizeof(*hdr); |
1155 | | |
1156 | | /* round up to full pages */ |
1157 | 0 | pagecnt = bufsz / pagesz; |
1158 | 0 | if (bufsz % pagesz) { |
1159 | 0 | pagecnt += 1; |
1160 | 0 | } |
1161 | 0 | bufsz = pagesz * pagecnt; |
1162 | |
|
1163 | 0 | if (orig_bufsz >= bufsz) { |
1164 | | /* integer wrap */ |
1165 | 0 | errno = ENOMEM; |
1166 | 0 | return NULL; |
1167 | 0 | } |
1168 | | |
1169 | 0 | #ifdef MAP_ANON |
1170 | | /* BSD */ |
1171 | 0 | buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, |
1172 | 0 | -1 /* fd */, 0 /* offset */); |
1173 | | #else |
1174 | | { |
1175 | | int saved_errno; |
1176 | | int fd; |
1177 | | |
1178 | | fd = open("/dev/zero", O_RDWR); |
1179 | | if (fd == -1) { |
1180 | | return NULL; |
1181 | | } |
1182 | | |
1183 | | buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, |
1184 | | fd, 0 /* offset */); |
1185 | | saved_errno = errno; |
1186 | | close(fd); |
1187 | | errno = saved_errno; |
1188 | | } |
1189 | | #endif |
1190 | |
|
1191 | 0 | if (buf == MAP_FAILED) { |
1192 | 0 | return NULL; |
1193 | 0 | } |
1194 | | |
1195 | 0 | hdr = (struct anonymous_shared_header *)buf; |
1196 | 0 | hdr->u.length = bufsz; |
1197 | |
|
1198 | 0 | ptr = (void *)(&hdr[1]); |
1199 | |
|
1200 | 0 | return ptr; |
1201 | 0 | } |
1202 | | |
1203 | | void *anonymous_shared_resize(void *ptr, size_t new_size, bool maymove) |
1204 | 0 | { |
1205 | 0 | #ifdef HAVE_MREMAP |
1206 | 0 | void *buf; |
1207 | 0 | size_t pagesz = getpagesize(); |
1208 | 0 | size_t pagecnt; |
1209 | 0 | size_t bufsz; |
1210 | 0 | struct anonymous_shared_header *hdr; |
1211 | 0 | int flags = 0; |
1212 | |
|
1213 | 0 | if (ptr == NULL) { |
1214 | 0 | errno = EINVAL; |
1215 | 0 | return NULL; |
1216 | 0 | } |
1217 | | |
1218 | 0 | hdr = (struct anonymous_shared_header *)ptr; |
1219 | 0 | hdr--; |
1220 | 0 | if (hdr->u.length > (new_size + sizeof(*hdr))) { |
1221 | 0 | errno = EINVAL; |
1222 | 0 | return NULL; |
1223 | 0 | } |
1224 | | |
1225 | 0 | bufsz = new_size + sizeof(*hdr); |
1226 | | |
1227 | | /* round up to full pages */ |
1228 | 0 | pagecnt = bufsz / pagesz; |
1229 | 0 | if (bufsz % pagesz) { |
1230 | 0 | pagecnt += 1; |
1231 | 0 | } |
1232 | 0 | bufsz = pagesz * pagecnt; |
1233 | |
|
1234 | 0 | if (new_size >= bufsz) { |
1235 | | /* integer wrap */ |
1236 | 0 | errno = ENOSPC; |
1237 | 0 | return NULL; |
1238 | 0 | } |
1239 | | |
1240 | 0 | if (bufsz <= hdr->u.length) { |
1241 | 0 | return ptr; |
1242 | 0 | } |
1243 | | |
1244 | 0 | if (maymove) { |
1245 | 0 | flags = MREMAP_MAYMOVE; |
1246 | 0 | } |
1247 | |
|
1248 | 0 | buf = mremap(hdr, hdr->u.length, bufsz, flags); |
1249 | |
|
1250 | 0 | if (buf == MAP_FAILED) { |
1251 | 0 | errno = ENOSPC; |
1252 | 0 | return NULL; |
1253 | 0 | } |
1254 | | |
1255 | 0 | hdr = (struct anonymous_shared_header *)buf; |
1256 | 0 | hdr->u.length = bufsz; |
1257 | |
|
1258 | 0 | ptr = (void *)(&hdr[1]); |
1259 | |
|
1260 | 0 | return ptr; |
1261 | | #else |
1262 | | errno = ENOSPC; |
1263 | | return NULL; |
1264 | | #endif |
1265 | 0 | } |
1266 | | |
1267 | | void anonymous_shared_free(void *ptr) |
1268 | 0 | { |
1269 | 0 | struct anonymous_shared_header *hdr; |
1270 | |
|
1271 | 0 | if (ptr == NULL) { |
1272 | 0 | return; |
1273 | 0 | } |
1274 | | |
1275 | 0 | hdr = (struct anonymous_shared_header *)ptr; |
1276 | |
|
1277 | 0 | hdr--; |
1278 | |
|
1279 | 0 | munmap(hdr, hdr->u.length); |
1280 | 0 | } |
1281 | | |
1282 | | #ifdef DEVELOPER |
1283 | | /* used when you want a debugger started at a particular point in the |
1284 | | code. Mostly useful in code that runs as a child process, where |
1285 | | normal gdb attach is harder to organise. |
1286 | | */ |
1287 | | void samba_start_debugger(void) |
1288 | 0 | { |
1289 | 0 | int ready_pipe[2]; |
1290 | 0 | char c; |
1291 | 0 | int ret; |
1292 | 0 | pid_t pid; |
1293 | |
|
1294 | 0 | ret = pipe(ready_pipe); |
1295 | 0 | SMB_ASSERT(ret == 0); |
1296 | | |
1297 | 0 | pid = fork(); |
1298 | 0 | SMB_ASSERT(pid >= 0); |
1299 | | |
1300 | 0 | if (pid) { |
1301 | 0 | c = 0; |
1302 | |
|
1303 | 0 | ret = close(ready_pipe[0]); |
1304 | 0 | SMB_ASSERT(ret == 0); |
1305 | 0 | #if defined(HAVE_PRCTL) && defined(PR_SET_PTRACER) |
1306 | | /* |
1307 | | * Make sure the child process can attach a debugger. |
1308 | | * |
1309 | | * We don't check the error code as the debugger |
1310 | | * will tell us if it can't attach. |
1311 | | */ |
1312 | 0 | (void)prctl(PR_SET_PTRACER, pid, 0, 0, 0); |
1313 | 0 | #endif |
1314 | 0 | ret = write(ready_pipe[1], &c, 1); |
1315 | 0 | SMB_ASSERT(ret == 1); |
1316 | | |
1317 | 0 | ret = close(ready_pipe[1]); |
1318 | 0 | SMB_ASSERT(ret == 0); |
1319 | | |
1320 | | /* Wait for gdb to attach. */ |
1321 | 0 | sleep(2); |
1322 | 0 | } else { |
1323 | 0 | char *cmd = NULL; |
1324 | |
|
1325 | 0 | ret = close(ready_pipe[1]); |
1326 | 0 | SMB_ASSERT(ret == 0); |
1327 | | |
1328 | 0 | ret = read(ready_pipe[0], &c, 1); |
1329 | 0 | SMB_ASSERT(ret == 1); |
1330 | | |
1331 | 0 | ret = close(ready_pipe[0]); |
1332 | 0 | SMB_ASSERT(ret == 0); |
1333 | | |
1334 | 0 | ret = asprintf(&cmd, "gdb --pid %u", getppid()); |
1335 | 0 | SMB_ASSERT(ret != -1); |
1336 | | |
1337 | 0 | execlp("xterm", "xterm", "-e", cmd, (char *) NULL); |
1338 | 0 | smb_panic("execlp() failed"); |
1339 | 0 | } |
1340 | 0 | } |
1341 | | #endif |