summaryrefslogtreecommitdiff
path: root/examples/misc/openauth.c
blob: efd21c374f55c47957c12e4859956568c95fcc76 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/* This is a copy of the hellolibvirt example demonstaring how to use
 * virConnectOpenAuth with a custom auth callback */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>

static void
showError(virConnectPtr conn)
{
    int ret;
    virErrorPtr err;

    err = malloc(sizeof(*err));
    if (err == NULL) {
        printf("Could not allocate memory for error data\n");
        goto out;
    }

    ret = virConnCopyLastError(conn, err);

    switch (ret) {
    case 0:
        printf("No error found\n");
        break;

    case -1:
        printf("Parameter error when attempting to get last error\n");
        break;

    default:
        printf("libvirt reported: \"%s\"\n", err->message);
        break;
    }

    virResetError(err);
    free(err);

 out:
    return;
}


static int
showHypervisorInfo(virConnectPtr conn)
{
    int ret = 0;
    unsigned long hvVer, major, minor, release;
    const char *hvType;

    /* virConnectGetType returns a pointer to a static string, so no
     * allocation or freeing is necessary; it is possible for the call
     * to fail if, for example, there is no connection to a
     * hypervisor, so check what it returns. */
    hvType = virConnectGetType(conn);
    if (hvType == NULL) {
        ret = 1;
        printf("Failed to get hypervisor type\n");
        showError(conn);
        goto out;
    }

    if (virConnectGetVersion(conn, &hvVer) != 0) {
        ret = 1;
        printf("Failed to get hypervisor version\n");
        showError(conn);
        goto out;
    }

    major = hvVer / 1000000;
    hvVer %= 1000000;
    minor = hvVer / 1000;
    release = hvVer % 1000;

    printf("Hypervisor: \"%s\" version: %lu.%lu.%lu\n",
           hvType,
           major,
           minor,
           release);

 out:
    return ret;
}


static int
showDomains(virConnectPtr conn)
{
    int ret = 0, numNames, numInactiveDomains, numActiveDomains;
    ssize_t i;
    char **nameList = NULL;

    numActiveDomains = virConnectNumOfDomains(conn);
    if (numActiveDomains == -1) {
        ret = 1;
        printf("Failed to get number of active domains\n");
        showError(conn);
        goto out;
    }

    numInactiveDomains = virConnectNumOfDefinedDomains(conn);
    if (numInactiveDomains == -1) {
        ret = 1;
        printf("Failed to get number of inactive domains\n");
        showError(conn);
        goto out;
    }

    printf("There are %d active and %d inactive domains\n",
           numActiveDomains, numInactiveDomains);

    nameList = malloc(sizeof(*nameList) * numInactiveDomains);

    if (nameList == NULL) {
        ret = 1;
        printf("Could not allocate memory for list of inactive domains\n");
        goto out;
    }

    numNames = virConnectListDefinedDomains(conn,
                                            nameList,
                                            numInactiveDomains);

    if (numNames == -1) {
        ret = 1;
        printf("Could not get list of defined domains from hypervisor\n");
        showError(conn);
        goto out;
    }

    if (numNames > 0)
        printf("Inactive domains:\n");

    for (i = 0; i < numNames; i++) {
        printf("  %s\n", *(nameList + i));
        /* The API documentation doesn't say so, but the names
         * returned by virConnectListDefinedDomains are strdup'd and
         * must be freed here.  */
        free(*(nameList + i));
    }

 out:
    free(nameList);
    return ret;
}

/* Struct to pass the credentials to the auth callback via the cbdata pointer */
struct _AuthData {
    char *username;
    char *password;
};

typedef struct _AuthData AuthData;

/* This function will be called by libvirt to obtain credentials in order to
 * authenticate to the hypervisor */
static int
authCallback(virConnectCredentialPtr cred, unsigned int ncred, void *cbdata)
{
    size_t i;
    AuthData *authData = cbdata;

    /* libvirt might request multiple credentials in a single call.
     * This example supports VIR_CRED_AUTHNAME and VIR_CRED_PASSPHRASE
     * credentials only, but there are several other types.
     *
     * A request may also contain a prompt message that can be displayed
     * to the user and a challenge. The challenge is specific to the
     * credential type and hypervisor type.
     *
     * For example the ESX driver passes the hostname of the ESX or vCenter
     * server as challenge. This allows a auth callback to return the
     * proper credentials. */
    for (i = 0; i < ncred; ++i) {
        switch (cred[i].type) {
        case VIR_CRED_AUTHNAME:
            cred[i].result = strdup(authData->username);

            if (cred[i].result == NULL)
                return -1;

            cred[i].resultlen = strlen(cred[i].result);
            break;

        case VIR_CRED_PASSPHRASE:
            cred[i].result = strdup(authData->password);

            if (cred[i].result == NULL)
                return -1;

            cred[i].resultlen = strlen(cred[i].result);
            break;

        default:
            return -1;
        }
    }

    return 0;
}


/* The list of credential types supported by our auth callback */
static int credTypes[] = {
    VIR_CRED_AUTHNAME,
    VIR_CRED_PASSPHRASE
};


/* The auth struct that will be passed to virConnectOpenAuth */
static virConnectAuth auth = {
    credTypes,
    sizeof(credTypes) / sizeof(int),
    authCallback,
    NULL, /* cbdata will be initialized in main */
};


int
main(int argc, char *argv[])
{
    int ret = 0;
    virConnectPtr conn;
    char *uri;
    AuthData authData;

    if (argc != 4) {
        ret = 1;
        printf("Usage: %s <uri> <username> <password>\n", argv[0]);
        goto out;
    }

    uri = argv[1];
    authData.username = argv[2];
    authData.password = argv[3];
    auth.cbdata = &authData;

    printf("Attempting to connect to hypervisor\n");

    conn = virConnectOpenAuth(uri, &auth, 0);

    if (NULL == conn) {
        ret = 1;
        printf("No connection to hypervisor\n");
        showError(conn);
        goto out;
    }

    uri = virConnectGetURI(conn);
    if (uri == NULL) {
        ret = 1;
        printf("Failed to get URI for hypervisor connection\n");
        showError(conn);
        goto disconnect;
    }

    printf("Connected to hypervisor at \"%s\"\n", uri);
    free(uri);

    if (showHypervisorInfo(conn) != 0) {
        ret = 1;
        goto disconnect;
    }

    if (showDomains(conn) != 0) {
        ret = 1;
        goto disconnect;
    }

 disconnect:
    if (virConnectClose(conn) != 0) {
        printf("Failed to disconnect from hypervisor\n");
        showError(conn);
        ret = 1;
    } else {
        printf("Disconnected from hypervisor\n");
    }

 out:
    return ret;
}