💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › c5d868bff133f435e52df7e35af35… captured on 2024-02-05 at 09:58:34. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

Go Back

0 /*

1 * ISC License

2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>

3 */

4

5 #include <stdio.h>

6 #include <stdlib.h>

7 #include <stdint.h>

8 #include <string.h>

9 #include <time.h>

10 #include "macro.h"

11 #include "strlcpy.h"

12 #define KNOWN_HOSTS_INTERNAL

13 #include "known_hosts.h"

14 #include "storage.h"

15 #include "error.h"

16

17 #define FILENAME "known_hosts"

18 #ifdef __OpenBSD__

19 #define TIME_T "%lld"

20 #else

21 #define TIME_T "%ld"

22 #endif

23

24 #define HT_MOD (HT_SIZE - 1)

25

26 struct known_host *known_hosts[HT_SIZE] = {NULL};

27

28 const uint32_t fnv_prime = 0x01000193;

29 const uint32_t fnv_offset = 0x811C9DC5;

30 static uint32_t fnv1a(const uint8_t *data, size_t length) {

31 uint32_t hash = fnv_offset;

32 size_t i;

33 for (i = 0; i < length; i++)

34 hash = (hash ^ data[i]) * fnv_prime;

35 return hash;

36 }

37 #define FNV1A(X) (fnv1a((uint8_t*)X, strlen(X)) & HT_MOD)

38

39 int known_hosts_add(const char *host, const char *hash,

40 time_t start, time_t end) {

41 struct known_host **ptr;

42 int index = FNV1A(host);

43 for (ptr = &known_hosts[index]; *ptr; ptr = &((*ptr)->next)) ;

44 *ptr = calloc(1, sizeof(struct known_host));

45 if (!*ptr) return ERROR_MEMORY_FAILURE;

46

47 STRLCPY((*ptr)->host, host);

48 STRLCPY((*ptr)->hash, hash);

49 (*ptr)->start = start;

50 (*ptr)->end = end;

51 return 0;

52 }

53

54 int known_hosts_load(void) {

55

56 FILE *f;

57 int ch = !EOF;

58 int ret = 0;

59 ASSERT((HT_SIZE & HT_MOD) == 0);

60

61 f = storage_fopen(FILENAME, "r");

62 if (!f) return 0;

63

64 while (ch != EOF) {

65

66 char line[1024] = {0};

67 char *host, *hash, *start, *end;

68 size_t i;

69 struct known_host known_host;

70

71 for (i = 0; i < sizeof(line); i++) {

72 ch = getc(f);

73 if (ch == EOF || ch == '\n') break;

74 if (ch == '\t') ch = ' ';

75 if (i > 0 && ch == ' ' && line[i - 1] == ' ') i--;

76 line[i] = ch;

77 }

78 if (i == sizeof(line)) continue;

79 line[i] = '\0';

80

81 host = line;

82

83 hash = strchr(host, ' ');

84 if (!hash) continue;

85 *(hash++) = '\0';

86

87 start = strchr(hash, ' ');

88 if (!start) continue;

89 *(start++) = '\0';

90

91 end = strchr(start, ' ');

92 if (!end) continue;

93 *(end++) = '\0';

94

95 known_host.start = strtoll(start, NULL, 10);

96 if (!known_host.start) continue;

97 known_host.end = strtoll(end, NULL, 10);

98 if (!known_host.end) continue;

99

100 if ((ret = known_hosts_add(host, hash,

101 known_host.start, known_host.end))) {

102 return ret;

103 }

104 }

105

106 fclose(f);

107 return ret;

108 }

109

110 int known_hosts_write(const char *host, const char *hash,

111 time_t start, time_t end) {

112 FILE *f;

113 f = storage_fopen(FILENAME, "a");

114 if (!f) return ERROR_STORAGE_ACCESS;

115 fprintf(f, "%s %s "TIME_T" "TIME_T"\n", host, hash, start, end);

116 fclose(f);

117 return 0;

118 }

119

120 int known_hosts_rewrite(void) {

121 FILE *f;

122 int i;

123

124 f = storage_fopen(FILENAME, "w");

125 if (!f) return ERROR_STORAGE_ACCESS;

126

127 for (i = 0; i < HT_SIZE; i++) {

128 struct known_host *ptr;

129 for (ptr = known_hosts[i]; ptr; ptr = ptr->next) {

130 fprintf(f, "%s %s "TIME_T" "TIME_T"\n",

131 ptr->host, ptr->hash, ptr->start, ptr->end);

132 }

133 }

134 fclose(f);

135 return 0;

136 }

137

138 struct known_host *known_hosts_get(const char *host) {

139 int index = FNV1A(host);

140 struct known_host *ptr = known_hosts[index];

141 for (; ptr; ptr = ptr->next) {

142 if (!strcmp(ptr->host, host)) break;

143 }

144 return ptr;

145 }

146

147 int known_hosts_verify(const char *host, const char *hash,

148 time_t start, time_t end) {

149

150 time_t now = time(NULL);

151 int ret;

152 struct known_host *ptr = known_hosts_get(host);

153 if (!ptr) {

154 if ((ret = known_hosts_add(host, hash, start, end)))

155 return ret;

156 return known_hosts_write(host, hash, start, end);

157 }

158 if (ptr->end < now) {

159 if (start > now) return ERROR_CERTIFICATE_AHEAD;

160 /* old certificate expired, accept new certificate */

161 STRLCPY(ptr->hash, hash);

162 ptr->start = start;

163 ptr->end = end;

164 return known_hosts_rewrite();

165 }

166 if (strcmp(ptr->hash, hash))

167 return ERROR_CERTIFICATE_MISMATCH;

168 if (ptr->end < now)

169 return ERROR_CERTIFICATE_EXPIRED;

170 return 0;

171 }

172

173 int known_hosts_forget(const char *host) {

174 struct known_host *ptr, *prev = NULL;

175 int index = FNV1A(host);

176 for (ptr = known_hosts[index]; ptr; ptr = ptr->next) {

177 if (!strcmp(ptr->host, host)) break;

178 prev = ptr;

179 }

180 if (!ptr) return ERROR_INVALID_ARGUMENT;

181 if (prev) prev->next = ptr->next;

182 else known_hosts[index] = ptr->next;

183 free(ptr);

184 return known_hosts_rewrite();

185 }

186

187 int known_hosts_expired(const char *host) {

188 struct known_host *ptr = known_hosts_get(host);

189 if (!ptr) return -1;

190 return time(NULL) > ptr->end;

191 }

192

193 void known_hosts_free(void) {

194 int i;

195 for (i = 0; i < HT_SIZE; i++) {

196 struct known_host *ptr, *next = NULL;

197 for (ptr = known_hosts[i]; ptr; ptr = next) {

198 next = ptr->next;

199 free(ptr);

200 }

201 }

202 }

203