s4:heimdal: import lorikeet-heimdal-202201172009 (commit 5a0b45cd723628b3690ea848548b...
[samba.git] / source4 / heimdal / lib / hx509 / file.c
index 4f7e87f070ae9aa44c29262da09e3c1c681b7fb9..1b5ca3eae7105fb6921d852399ea39faf6ea7af2 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "hx_locl.h"
 
-int
+HX509_LIB_FUNCTION int HX509_LIB_CALL
 _hx509_map_file_os(const char *fn, heim_octet_string *os)
 {
     size_t length;
@@ -48,13 +48,13 @@ _hx509_map_file_os(const char *fn, heim_octet_string *os)
     return ret;
 }
 
-void
+HX509_LIB_FUNCTION void HX509_LIB_CALL
 _hx509_unmap_file_os(heim_octet_string *os)
 {
     rk_xfree(os->data);
 }
 
-int
+HX509_LIB_FUNCTION int HX509_LIB_CALL
 _hx509_write_file(const char *fn, const void *data, size_t length)
 {
     rk_dumpdata(fn, data, length);
@@ -71,7 +71,7 @@ print_pem_stamp(FILE *f, const char *type, const char *str)
     fprintf(f, "-----%s %s-----\n", type, str);
 }
 
-int
+HX509_LIB_FUNCTION int HX509_LIB_CALL
 hx509_pem_write(hx509_context context, const char *type,
                hx509_pem_header *headers, FILE *f,
                const void *data, size_t size)
@@ -98,7 +98,7 @@ hx509_pem_write(hx509_context context, const char *type,
        if (length > ENCODE_LINE_LENGTH)
            length = ENCODE_LINE_LENGTH;
 
-       l = base64_encode(p, length, &line);
+       l = rk_base64_encode(p, length, &line);
        if (l < 0) {
            hx509_set_error_string(context, 0, ENOMEM,
                                   "malloc - out of memory");
@@ -119,7 +119,7 @@ hx509_pem_write(hx509_context context, const char *type,
  *
  */
 
-int
+HX509_LIB_FUNCTION int HX509_LIB_CALL
 hx509_pem_add_header(hx509_pem_header **headers,
                     const char *header, const char *value)
 {
@@ -146,7 +146,7 @@ hx509_pem_add_header(hx509_pem_header **headers,
     return 0;
 }
 
-void
+HX509_LIB_FUNCTION void HX509_LIB_CALL
 hx509_pem_free_header(hx509_pem_header *headers)
 {
     hx509_pem_header *h;
@@ -163,7 +163,7 @@ hx509_pem_free_header(hx509_pem_header *headers)
  *
  */
 
-const char *
+HX509_LIB_FUNCTION const char * HX509_LIB_CALL
 hx509_pem_find_header(const hx509_pem_header *h, const char *header)
 {
     while(h) {
@@ -179,7 +179,7 @@ hx509_pem_find_header(const hx509_pem_header *h, const char *header)
  *
  */
 
-int
+HX509_LIB_FUNCTION int HX509_LIB_CALL
 hx509_pem_read(hx509_context context,
               FILE *f,
               hx509_pem_read_func func,
@@ -230,7 +230,7 @@ hx509_pem_read(hx509_context context,
                where = INDATA;
                goto indata;
            }
-           /* FALLTHOUGH */
+           /* FALLTHROUGH */
        case INHEADER:
            if (buf[0] == '\0') {
                where = INDATA;
@@ -255,7 +255,7 @@ hx509_pem_read(hx509_context context,
            }
 
            p = emalloc(i);
-           i = base64_decode(buf, p);
+           i = rk_base64_decode(buf, p);
            if (i < 0) {
                free(p);
                goto out;
@@ -300,3 +300,90 @@ hx509_pem_read(hx509_context context,
 
     return ret;
 }
+
+/*
+ * On modern systems there's no such thing as scrubbing a file.  Not this way
+ * anyways.  However, for now we'll cargo-cult this along just as in lib/krb5.
+ */
+static int
+scrub_file(int fd, ssize_t sz)
+{
+    char buf[128];
+
+    memset(buf, 0, sizeof(buf));
+    while (sz > 0) {
+        ssize_t tmp;
+        size_t wr = sizeof(buf) > sz ? (size_t)sz : sizeof(buf);
+
+        tmp = write(fd, buf, wr);
+        if (tmp == -1)
+            return errno;
+        sz -= tmp;
+    }
+#ifdef _MSC_VER
+    return _commit(fd);
+#else
+    return fsync(fd);
+#endif
+}
+
+int
+_hx509_erase_file(hx509_context context, const char *fn)
+{
+    struct stat sb1, sb2;
+    int ret;
+    int fd;
+
+    if (fn == NULL)
+        return 0;
+
+    /* This is based on _krb5_erase_file(), minus file locking */
+    ret = lstat(fn, &sb1);
+    if (ret == -1 && errno == ENOENT)
+        return 0;
+    if (ret == -1) {
+        hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: "
+                               "stat of \"%s\": %s", fn, strerror(ret));
+        return errno;
+    }
+
+    fd = open(fn, O_RDWR | O_BINARY | O_CLOEXEC | O_NOFOLLOW);
+    rk_cloexec(fd);
+    if (ret == -1 && errno == ENOENT)
+        return 0;
+    if (ret == -1)
+        return errno;
+
+    if (unlink(fn) < 0) {
+       ret = errno;
+        (void) close(fd);
+        hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: "
+                               "unlinking \"%s\": %s", fn, strerror(ret));
+        return ret;
+    }
+
+    /* check TOCTOU, symlinks */
+    ret = fstat(fd, &sb2);
+    if (ret < 0) {
+       ret = errno;
+        hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: "
+                               "fstat of %d, \"%s\": %s", fd, fn,
+                               strerror(ret));
+       (void) close(fd);
+       return ret;
+    }
+    if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
+       (void) close(fd);
+       return EPERM;
+    }
+
+    /* there are still hard links to this file */
+    if (sb2.st_nlink != 0) {
+        close(fd);
+        return 0;
+    }
+
+    ret = scrub_file(fd, sb2.st_size);
+    (void) close(fd);
+    return ret;
+}