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