1 /* Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net> */
2 /* Date: Fri, 04 Apr 2008 19:31:16 -0400 */
3 /* License: GPL v3 or later */
5 #include "gnutls-helpers.h"
18 void err(const char* fmt, ...) {
21 vfprintf(stderr, fmt, ap);
25 void logfunc(int level, const char* string) {
26 fprintf(stderr, "GnuTLS Logging (%d): %s\n", level, string);
29 void init_keyid(gnutls_openpgp_keyid_t keyid) {
30 memset(keyid, 'x', sizeof(gnutls_openpgp_keyid_t));
35 void make_keyid_printable(printable_keyid out, gnutls_openpgp_keyid_t keyid)
37 static const char hex[16] = "0123456789ABCDEF";
38 unsigned int kix = 0, outix = 0;
40 while (kix < sizeof(gnutls_openpgp_keyid_t)) {
41 out[outix] = hex[(keyid[kix] >> 4) & 0x0f];
42 out[outix + 1] = hex[keyid[kix] & 0x0f];
50 const char* version = NULL;
51 const char* debug_string = NULL;
54 if (ret = gnutls_global_init(), ret) {
55 err("Failed to do gnutls_global_init() (error: %d)\n", ret);
59 version = gnutls_check_version(NULL);
62 err("gnutls version: %s\n", version);
64 err("no version found!\n");
68 if (debug_string = getenv("MONKEYSPHERE_DEBUG"), debug_string) {
69 loglevel = atoi(debug_string);
70 gnutls_global_set_log_function(logfunc);
72 gnutls_global_set_log_level(loglevel);
73 err("set log level to %d\n", loglevel);
78 void init_datum(gnutls_datum_t* d) {
82 void copy_datum(gnutls_datum_t* dest, const gnutls_datum_t* src) {
83 dest->data = gnutls_realloc(dest->data, src->size);
84 dest->size = src->size;
85 memcpy(dest->data, src->data, src->size);
87 int compare_data(const gnutls_datum_t* a, const gnutls_datum_t* b) {
88 if (a->size > b->size) {
92 if (a->size < b->size) {
96 return memcmp(a->data, b->data, a->size);
98 void free_datum(gnutls_datum_t* d) {
104 /* read the passed-in string, store in a single datum */
105 int set_datum_string(gnutls_datum_t* d, const char* s) {
106 unsigned int x = strlen(s)+1;
107 unsigned char* c = NULL;
109 c = gnutls_realloc(d->data, x);
114 memcpy(d->data, s, x);
118 /* read the passed-in file descriptor until EOF, store in a single
120 int set_datum_fd(gnutls_datum_t* d, int fd) {
121 unsigned int bufsize = 1024;
122 unsigned int len = 0;
124 FILE* f = fdopen(fd, "r");
125 if (bufsize > d->size) {
127 d->data = gnutls_realloc(d->data, bufsize);
128 if (d->data == NULL) {
129 err("out of memory!\n");
138 err("could not fdopen FD %d\n", fd);
141 while (!feof(f) && !ferror(f)) {
142 if (len == bufsize) {
143 /* allocate more space by doubling: */
145 d->data = gnutls_realloc(d->data, bufsize);
146 if (d->data == NULL) {
147 err("out of memory!\n");
152 len += fread(d->data + len, 1, bufsize - len, f);
153 /* err("read %d bytes\n", len); */
156 err("Error reading from fd %d (error: %d) (error: %d '%s')\n", fd, ferror(f), errno, strerror(errno));
160 /* touch up buffer size to match reality: */
161 d->data = gnutls_realloc(d->data, len);
166 /* read the file indicated (by name) in the fname parameter. store
167 its entire contents in a single datum. */
168 int set_datum_file(gnutls_datum_t* d, const char* fname) {
170 unsigned char* c = NULL;
174 if (0 != stat(fname, &sbuf)) {
175 err("failed to stat '%s'\n", fname);
179 c = gnutls_realloc(d->data, sbuf.st_size);
181 err("failed to allocate %d bytes for '%s'\n", sbuf.st_size, fname);
186 d->size = sbuf.st_size;
187 file = fopen(fname, "r");
189 err("failed to open '%s' for reading\n", fname);
193 x = fread(d->data, d->size, 1, file);
195 err("tried to read %d bytes, read %d instead from '%s'\n", d->size, x, fname);
203 int write_datum_fd(int fd, const gnutls_datum_t* d) {
204 if (d->size != write(fd, d->data, d->size)) {
205 err("failed to write body of datum.\n");
212 int write_datum_fd_with_length(int fd, const gnutls_datum_t* d) {
213 uint32_t len = htonl(d->size);
214 if (write(fd, &len, sizeof(len)) != sizeof(len)) {
215 err("failed to write size of datum.\n");
218 return write_datum_fd(fd, d);
221 int write_data_fd_with_length(int fd, const gnutls_datum_t** d, unsigned int num) {
225 for (i = 0; i < num; i++)
226 if (ret = write_datum_fd_with_length(fd, d[i]), ret != 0)
233 int datum_from_string(gnutls_datum_t* d, const char* str) {
234 d->size = strlen(str);
235 d->data = gnutls_realloc(d->data, d->size);
238 memcpy(d->data, str, d->size);
243 int create_writing_pipe(pid_t* pid, const char* path, char* const argv[]) {
248 err("bad pointer passed to create_writing_pipe()\n");
252 if (ret = pipe(p), ret == -1) {
253 err("failed to create a pipe (error: %d \"%s\")\n", errno, strerror(errno));
259 err("Failed to fork (error: %d \"%s\")\n", errno, strerror(errno));
262 if (*pid == 0) { /* this is the child */
263 close(p[1]); /* close unused write end */
265 if (0 != dup2(p[0], 0)) { /* map the reading end into stdin */
266 err("Failed to transfer reading file descriptor to stdin (error: %d \"%s\")\n", errno, strerror(errno));
270 err("exec %s failed (error: %d \"%s\")\n", path, errno, strerror(errno));
272 } else { /* this is the parent */
273 close(p[0]); /* close unused read end */
278 int validate_ssh_host_userid(const char* userid) {
279 char* oldlocale = setlocale(LC_ALL, "C");
281 /* choke if userid does not match the expected format
282 ("ssh://fully.qualified.domain.name") */
283 if (strncmp("ssh://", userid, strlen("ssh://")) != 0) {
284 err("The user ID should start with ssh:// for a host key\n");
287 /* so that isalnum will work properly */
288 userid += strlen("ssh://");
289 while (0 != (*userid)) {
290 if (!isalnum(*userid)) {
291 err("label did not start with a letter or a digit! (%s)\n", userid);
295 while (isalnum(*userid) || ('-' == (*userid)))
297 if (('.' == (*userid)) || (0 == (*userid))) { /* clean end of label:
300 if (!isalnum(*(userid - 1))) {
301 err("label did not end with a letter or a digit!\n");
304 if ('.' == (*userid)) /* advance to the start of the next label */
307 err("invalid character in domain name: %c\n", *userid);
311 /* ensure that the last character is valid: */
312 if (!isalnum(*(userid - 1))) {
313 err("hostname did not end with a letter or a digit!\n");
316 /* FIXME: fqdn's can be unicode now, thanks to RFC 3490 -- how do we
317 make sure that we've got an OK string? */
322 setlocale(LC_ALL, oldlocale);