From a808accd1e748184933f0e4d97d499d79f34f889 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 23 Jan 2019 01:19:46 +0100 Subject: Replace tempnam() with mkstemp() and provide reference implementation for systems lacking it --- configure.ac | 2 +- src/common.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/common.h | 2 + src/idevicerestore.c | 2 +- src/restore.c | 13 ++-- 5 files changed, 189 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 94a9a79..c67c0ac 100644 --- a/configure.ac +++ b/configure.ac @@ -59,7 +59,7 @@ case "$host_os" in ;; esac -AC_CHECK_FUNCS([strsep strcspn]) +AC_CHECK_FUNCS([strsep strcspn mkstemp]) if test x$ac_cv_func_strsep != xyes; then if test x$ac_cv_func_strcspn != xyes; then AC_MSG_ERROR([You need either strsep or strcspn to build $PACKAGE]) diff --git a/src/common.c b/src/common.c index c3d835f..59e37a5 100644 --- a/src/common.c +++ b/src/common.c @@ -28,10 +28,25 @@ #include #include #include +#include #include #include #include #include +#include + +#ifdef WIN32 +#include +#ifndef _O_EXCL +#define _O_EXCL 0x0400 +#endif +#ifndef O_EXCL +#define O_EXCL _O_EXCL +#endif +#else +#include +#include +#endif #include "common.h" @@ -280,6 +295,168 @@ int mkdir_with_parents(const char *dir, int mode) return res; } +#ifndef HAVE_MKSTEMP +/* Based on libc's __gen_tempname() from sysdeps/posix/tempname.c + Copyright (C) 1991-2018 Free Software Foundation, Inc. + With changes from https://stackoverflow.com/a/6036308 and some + additional changes. */ +int mkstemp(char *tmpl) +{ + static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + int len; + char *XXXXXX; + static unsigned long long value; + unsigned long long random_time_bits; + unsigned int count; + int fd = -1; + int save_errno = errno; + + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6. It should never be + necessary to try all these combinations. Instead if a reasonable + number of names is tried (we define reasonable as 62**3) fail to + give the system administrator the chance to remove the problems. */ +#define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To + conform to POSIX, this must be no smaller than TMP_MAX. */ +#if ATTEMPTS_MIN < TMP_MAX + unsigned int attempts = TMP_MAX; +#else + unsigned int attempts = ATTEMPTS_MIN; +#endif + + len = strlen (tmpl); + if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) + { + errno = EINVAL; + return -1; + } + + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6]; + + /* Get some more or less random data. */ +#ifdef WIN32 + { + SYSTEMTIME stNow; + FILETIME ftNow; + + // get system time + GetSystemTime(&stNow); + if (!SystemTimeToFileTime(&stNow, &ftNow)) + { + errno = -1; + return -1; + } + + random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32) + | (unsigned long long)ftNow.dwLowDateTime); + } + value += random_time_bits ^ ((unsigned long long)GetCurrentProcessId() << 32 | (unsigned long long)GetCurrentThreadId()); +#else + { + struct timeval tvNow = {0, 0}; + gettimeofday(&tvNow, NULL); + random_time_bits = (((unsigned long long)tvNow.tv_sec << 32) + | (unsigned long long)tvNow.tv_usec); + } + value += random_time_bits ^ ((unsigned long long)getpid() << 32 | (unsigned long long)(uintptr_t)pthread_self()); +#endif + + for (count = 0; count < attempts; value += 7777, ++count) + { + unsigned long long v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + +#ifdef WIN32 + fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE); +#else + fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +#endif + if (fd >= 0) + { + errno = save_errno; + return fd; + } + else if (errno != EEXIST) + return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + errno = EEXIST; + return -1; +} +#endif + +char *get_temp_filename(const char *prefix) +{ + char *result = NULL; + char *tmpdir; + size_t lt; + size_t lp; + const char *TMPVARS[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", NULL }; + int i = 0; + int fd; + + /* check the prefix parameter */ + if (!prefix) { + prefix = "tmp_"; + } +#ifdef WIN32 + if (strchr(prefix, '/') || strchr(prefix, '\\')) return NULL; +#else + if (strchr(prefix, '/')) return NULL; +#endif + + while (TMPVARS[i] && ((tmpdir = getenv(TMPVARS[i])) == NULL)) i++; + if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) { +#ifdef WIN32 + tmpdir = "C:\\WINDOWS\\TEMP"; +#else + tmpdir = P_tmpdir; +#endif + } + if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) { + return NULL; + } + + lt = strlen(tmpdir); + if (lt < 1) { + return NULL; + } + lp = strlen(prefix); + result = malloc(lt + lp + 8); + strncpy(result, tmpdir, lt); +#ifdef WIN32 + if (tmpdir[lt-1] != '/' && tmpdir[lt-1] != '\\') result[lt++] = '\\'; +#else + if (tmpdir[lt-1] != '/') result[lt++] = '/'; +#endif + strncpy(result + lt, prefix, lp); + strcpy(result + lt + lp, "XXXXXX"); + fd = mkstemp(result); + if (fd < 0) { + free(result); + result = NULL; + } + close(fd); + return result; +} + void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress) { if(client && client->progress_cb) { diff --git a/src/common.h b/src/common.h index efa94f9..2f6beb3 100644 --- a/src/common.h +++ b/src/common.h @@ -136,6 +136,8 @@ char *generate_guid(void); int mkdir_with_parents(const char *dir, int mode); +char *get_temp_filename(const char *prefix); + void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress); #ifndef HAVE_STRSEP diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3a496de..822601c 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -629,7 +629,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) unlock_file(&li); if (!extf) { // use temp filename - filesystem = tempnam(NULL, "ipsw_"); + filesystem = get_temp_filename("ipsw_"); if (!filesystem) { error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname); filesystem = strdup(fsname); diff --git a/src/restore.c b/src/restore.c index 6652aa0..a187dfa 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1627,15 +1627,18 @@ int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_ } // extract baseband firmware to temp file - bbfwtmp = tempnam(NULL, client->udid); + bbfwtmp = get_temp_filename("bbfw_"); if (!bbfwtmp) { - error("WARNING: Could not generate temporary filename, using bbfw.tmp\n"); - bbfwtmp = strdup("bbfw.tmp"); + size_t l = strlen(client->udid); + bbfwtmp = malloc(l + 10); + strcpy(bbfwtmp, "bbfw_"); + strncpy(bbfwtmp + 5, client->udid, l); + strcpy(bbfwtmp + 5 + l, ".tmp"); + error("WARNING: Could not generate temporary filename, using %s in current directory\n", bbfwtmp); } if (ipsw_extract_to_file(client->ipsw, bbfwpath, bbfwtmp) != 0) { error("ERROR: Unable to extract baseband firmware from ipsw\n"); - plist_free(response); - return -1; + goto leave; } if (bb_nonce && !client->restore->bbtss) { -- cgit v1.1-32-gdbae