Home | History | Annotate | Line # | Download | only in ServiceRegistration
srp-filedata.c revision 1.1
      1  1.1  christos /* srp-ioloop.c
      2  1.1  christos  *
      3  1.1  christos  * Copyright (c) 2019 Apple Computer, Inc. All rights reserved.
      4  1.1  christos  *
      5  1.1  christos  * Licensed under the Apache License, Version 2.0 (the "License");
      6  1.1  christos  * you may not use this file except in compliance with the License.
      7  1.1  christos  * You may obtain a copy of the License at
      8  1.1  christos  *
      9  1.1  christos  *     http://www.apache.org/licenses/LICENSE-2.0
     10  1.1  christos  *
     11  1.1  christos  * Unless required by applicable law or agreed to in writing, software
     12  1.1  christos  * distributed under the License is distributed on an "AS IS" BASIS,
     13  1.1  christos  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  1.1  christos  * See the License for the specific language governing permissions and
     15  1.1  christos  * limitations under the License.
     16  1.1  christos  *
     17  1.1  christos  * srp host API implementation for Posix using ioloop primitives.
     18  1.1  christos  */
     19  1.1  christos 
     20  1.1  christos #include <stdio.h>
     21  1.1  christos #include <arpa/inet.h>
     22  1.1  christos #include <string.h>
     23  1.1  christos #include <stdlib.h>
     24  1.1  christos #include <unistd.h>
     25  1.1  christos #include <dns_sd.h>
     26  1.1  christos #include <errno.h>
     27  1.1  christos #include <fcntl.h>
     28  1.1  christos 
     29  1.1  christos #include "srp.h"
     30  1.1  christos #include "srp-api.h"
     31  1.1  christos #include "dns-msg.h"
     32  1.1  christos #include "srp-crypto.h"
     33  1.1  christos #include "ioloop.h"
     34  1.1  christos 
     35  1.1  christos bool
     36  1.1  christos srp_load_file_data(void *host_context, const char *filename, uint8_t *buffer, uint16_t *length, uint16_t buffer_size)
     37  1.1  christos {
     38  1.1  christos     off_t flen;
     39  1.1  christos     ssize_t len;
     40  1.1  christos     int file;
     41  1.1  christos     (void)host_context;
     42  1.1  christos 
     43  1.1  christos     file = open(filename, O_RDONLY);
     44  1.1  christos     if (file < 0) {
     45  1.1  christos         ERROR("srp_load_file_data: %s: open: %s", filename, strerror(errno));
     46  1.1  christos         return false;
     47  1.1  christos     }
     48  1.1  christos 
     49  1.1  christos     // Get the length of the file.
     50  1.1  christos     flen = lseek(file, 0, SEEK_END);
     51  1.1  christos     lseek(file, 0, SEEK_SET);
     52  1.1  christos     if (flen > buffer_size) {
     53  1.1  christos         ERROR("srp_load_file_data: %s: lseek: %s", filename, strerror(errno));
     54  1.1  christos         close(file);
     55  1.1  christos         return false;
     56  1.1  christos     }
     57  1.1  christos     len = read(file, buffer, (size_t)flen); // Note: flen always positive, no loss of precision.
     58  1.1  christos     if (len < 0 || len != flen) {
     59  1.1  christos         if (len < 0) {
     60  1.1  christos             ERROR("srp_load_file_data: %s: read: %s", filename, strerror(errno));
     61  1.1  christos         } else {
     62  1.1  christos             ERROR("srp_load_file_data: %s: short read %d out of %d", filename, (int)len, (int)flen);
     63  1.1  christos         }
     64  1.1  christos         close(file);
     65  1.1  christos         return false;
     66  1.1  christos     }
     67  1.1  christos     close(file);
     68  1.1  christos     *length = (uint16_t)len;
     69  1.1  christos     return true;
     70  1.1  christos }
     71  1.1  christos 
     72  1.1  christos bool
     73  1.1  christos srp_store_file_data(void *host_context, const char *filename, uint8_t *buffer, uint16_t length)
     74  1.1  christos {
     75  1.1  christos     ssize_t len;
     76  1.1  christos     int file;
     77  1.1  christos     (void)host_context;
     78  1.1  christos     file = open(filename, O_WRONLY | O_CREAT, 0600);
     79  1.1  christos     if (file < 0) {
     80  1.1  christos         ERROR("srp_store_file_data: %s: %s", filename, strerror(errno));
     81  1.1  christos         return false;
     82  1.1  christos    }
     83  1.1  christos     len = write(file, buffer, length);
     84  1.1  christos     if (len < 0 || len != length) {
     85  1.1  christos         if (len < 0) {
     86  1.1  christos             ERROR("srp_store_file_data: " PUB_S_SRP ": " PUB_S_SRP, filename, strerror(errno));
     87  1.1  christos         } else {
     88  1.1  christos             ERROR("srp_store_file_data: short write %d out of %d on file " PUB_S_SRP, (int)len, (int)length, filename);
     89  1.1  christos         }
     90  1.1  christos         unlink(filename);
     91  1.1  christos         close(file);
     92  1.1  christos         return false;
     93  1.1  christos     }
     94  1.1  christos     close(file);
     95  1.1  christos     return true;
     96  1.1  christos }
     97  1.1  christos 
     98  1.1  christos 
     99  1.1  christos bool
    100  1.1  christos srp_get_last_server(uint16_t *NONNULL rrtype, uint8_t *NONNULL rdata, uint16_t rdlim,
    101  1.1  christos                     uint8_t *NONNULL port, void *NULLABLE host_context)
    102  1.1  christos {
    103  1.1  christos     uint8_t buffer[22];
    104  1.1  christos     unsigned offset = 0;
    105  1.1  christos     uint16_t length;
    106  1.1  christos     uint16_t rdlength;
    107  1.1  christos 
    108  1.1  christos     if (!srp_load_file_data(host_context, "/var/run/srp-last-server", buffer, &length, sizeof(buffer))) {
    109  1.1  christos         return false;
    110  1.1  christos     }
    111  1.1  christos     if (length < 10) { // rrtype + rdlength + ipv4 address + port
    112  1.1  christos         ERROR("srp_get_last_server: stored server data is too short: %d", length);
    113  1.1  christos         return false;
    114  1.1  christos     }
    115  1.1  christos     *rrtype = (((uint16_t)buffer[offset]) << 8) | buffer[offset + 1];
    116  1.1  christos     offset += 2;
    117  1.1  christos     rdlength = (((uint16_t)buffer[offset]) << 8) | buffer[offset + 1];
    118  1.1  christos     offset += 2;
    119  1.1  christos     if ((*rrtype == dns_rrtype_a && rdlength != 4) || (*rrtype == dns_rrtype_aaaa && rdlength != 16)) {
    120  1.1  christos         ERROR("srp_get_last_server: invalid rdlength %d for %s record",
    121  1.1  christos               rdlength, *rrtype == dns_rrtype_a ? "A" : "AAAA");
    122  1.1  christos         return false;
    123  1.1  christos     }
    124  1.1  christos     if (length < rdlength + 6) { // rrtype + rdlength + address + port
    125  1.1  christos         ERROR("srp_get_last_server: stored server data length %d is too short", length);
    126  1.1  christos         return false;
    127  1.1  christos     }
    128  1.1  christos     if (rdlength > rdlim) {
    129  1.1  christos         ERROR("srp_get_last_server: no space for %s data in provided buffer size %d",
    130  1.1  christos               *rrtype == dns_rrtype_a ? "A" : "AAAA", rdlim);
    131  1.1  christos         return false;
    132  1.1  christos     }
    133  1.1  christos     memcpy(rdata, &buffer[offset], rdlength);
    134  1.1  christos     offset += rdlength;
    135  1.1  christos     memcpy(port, &buffer[offset], 2);
    136  1.1  christos     return true;
    137  1.1  christos }
    138  1.1  christos 
    139  1.1  christos bool
    140  1.1  christos srp_save_last_server(uint16_t rrtype, uint8_t *NONNULL rdata, uint16_t rdlength,
    141  1.1  christos                      uint8_t *NONNULL port, void *NULLABLE host_context)
    142  1.1  christos {
    143  1.1  christos     dns_towire_state_t towire;
    144  1.1  christos     uint8_t buffer[24];
    145  1.1  christos     size_t length;
    146  1.1  christos     memset(&towire, 0, sizeof(towire));
    147  1.1  christos     towire.p = buffer;
    148  1.1  christos     towire.lim = towire.p + sizeof(buffer);
    149  1.1  christos 
    150  1.1  christos     if (rdlength != 4 && rdlength != 16) {
    151  1.1  christos         ERROR("srp_save_last_server: invalid IP address length %d", rdlength);
    152  1.1  christos         return false;
    153  1.1  christos     }
    154  1.1  christos     dns_u16_to_wire(&towire, rrtype);
    155  1.1  christos     dns_u16_to_wire(&towire, rdlength);
    156  1.1  christos     dns_rdata_raw_data_to_wire(&towire, rdata, rdlength);
    157  1.1  christos     dns_rdata_raw_data_to_wire(&towire, port, 2);
    158  1.1  christos 
    159  1.1  christos     if (towire.error) {
    160  1.1  christos         ERROR("srp_save_last_server: " PUB_S_SRP " at %d (%p:%p:%p) while constructing output buffer",
    161  1.1  christos               strerror(towire.error), towire.line, towire.p, towire.lim, buffer);
    162  1.1  christos         return false;
    163  1.1  christos     }
    164  1.1  christos 
    165  1.1  christos     length = towire.p - buffer;
    166  1.1  christos     if (!srp_store_file_data(host_context, "/var/run/srp-last-server", buffer, length)) {
    167  1.1  christos         return false;
    168  1.1  christos     }
    169  1.1  christos     return true;
    170  1.1  christos }
    171  1.1  christos 
    172  1.1  christos #ifdef SRP_CRYPTO_MBEDTLS
    173  1.1  christos int
    174  1.1  christos srp_load_key_data(void *host_context, const char *key_name, uint8_t *buffer, uint16_t *length, uint16_t buffer_size)
    175  1.1  christos {
    176  1.1  christos     if (srp_load_file_data(host_context, key_name, buffer, length, buffer_size)) {
    177  1.1  christos         return kDNSServiceErr_NoError;
    178  1.1  christos     }
    179  1.1  christos     return kDNSServiceErr_NoSuchKey;
    180  1.1  christos }
    181  1.1  christos 
    182  1.1  christos int
    183  1.1  christos srp_store_key_data(void *host_context, const char *key_name, uint8_t *buffer, uint16_t length)
    184  1.1  christos {
    185  1.1  christos     if (!srp_store_file_data(host_context, key_name, buffer, length)) {
    186  1.1  christos         return kDNSServiceErr_Unknown;
    187  1.1  christos     }
    188  1.1  christos     return kDNSServiceErr_NoError;
    189  1.1  christos }
    190  1.1  christos 
    191  1.1  christos int
    192  1.1  christos srp_remove_key_file(void *host_context, const char *key_name)
    193  1.1  christos {
    194  1.1  christos 	if (unlink(key_name) < 0) {
    195  1.1  christos 		return kDNSServiceErr_Unknown;
    196  1.1  christos 	}
    197  1.1  christos 	return kDNSServiceErr_NoError;
    198  1.1  christos }
    199  1.1  christos #endif // SRP_CRYPTO_MBEDTLS_INTERNAL
    200