summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/src/otrlextensions.c
blob: ddf0248bb71c5939c911ad472876590841a94d22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * otrlextensions.c - Off-the-Record Messaging library extensions
 *
 * Strongly based on parts of the Off-the-Record Messaging library,
 * Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
 *                          <otr@cypherpunks.ca>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of version 2.1 of the GNU Lesser General
 * Public License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/* system headers */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>

/* libgcrypt headers */
#include <gcrypt.h>

/* libotr headers */
#include <privkey.h>

#include "otrlextensions.h"

static gcry_error_t sexp_write(FILE* privf, gcry_sexp_t sexp)
{
    size_t buflen;
    char* buf;

    buflen = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
    buf = malloc(buflen);
    if (buf == NULL && buflen > 0) {
        return gcry_error(GPG_ERR_ENOMEM);
    }
    gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, buflen);

    fprintf(privf, "%s", buf);
    free(buf);

    return gcry_error(GPG_ERR_NO_ERROR);
}

static gcry_error_t account_write(FILE* privf, const char* accountname,
    const char* protocol, gcry_sexp_t privkey)
{
    gcry_error_t err;
    gcry_sexp_t names, protos = 0;

    fprintf(privf, " (account\n");

    err = gcry_sexp_build(&names, NULL, "(name %s)", accountname);
    if (!err) {
        err = sexp_write(privf, names);
        gcry_sexp_release(names);
    }
    if (!err) err = gcry_sexp_build(&protos, NULL, "(protocol %s)", protocol);
    if (!err) {
        err = sexp_write(privf, protos);
        gcry_sexp_release(protos);
    }
    if (!err) err = sexp_write(privf, privkey);

    fprintf(privf, " )\n");

    return err;
}

/* Store all keys of an OtrlUserState.
 * The FILE* must be open for reading and writing. */
gcry_error_t otrl_privkey_write_FILEp(OtrlUserState us, FILE* privf)
{
    OtrlPrivKey* p;

    /* Output the other keys we know */
    fprintf(privf, "(privkeys\n");

    for (p=us->privkey_root; p; p=p->next) {
        account_write(privf, p->accountname, p->protocol, p->privkey);
    }

    fprintf(privf, ")\n");

    fseek(privf, 0, SEEK_SET);

    return otrl_privkey_read_FILEp(us, privf);
}

/* Store all keys of an OtrlUserState. */
gcry_error_t otrl_privkey_write(OtrlUserState us, const wchar_t *filename)
{
    gcry_error_t err;
    FILE* privf;
#ifndef WIN32
    mode_t oldmask;
#endif

#ifndef WIN32
    oldmask = umask(077);
#endif
    privf = _wfopen(filename, L"w+b");
    if (!privf) {
#ifndef WIN32
        umask(oldmask);
#endif
        err = gcry_error_from_errno(errno);
        return err;
    }

    err = otrl_privkey_write_FILEp(us, privf);

    fclose(privf);
#ifndef WIN32
    umask(oldmask);
#endif
    return err;
}