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