LCOV - code coverage report
Current view: top level - lib/util - util.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 256 498 51.4 %
Date: 2024-06-13 04:01:37 Functions: 37 52 71.2 %

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

Generated by: LCOV version 1.13