1 /* This is a copy of the hellolibvirt example demonstaring how to use
2 * virConnectOpenAuth with a custom auth callback */
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <libvirt/libvirt.h>
8 #include <libvirt/virterror.h>
9
10 static void
showError(virConnectPtr conn)11 showError(virConnectPtr conn)
12 {
13 int ret;
14 virErrorPtr err;
15
16 err = malloc(sizeof(*err));
17 if (err == NULL) {
18 printf("Could not allocate memory for error data\n");
19 return;
20 }
21
22 ret = virConnCopyLastError(conn, err);
23
24 switch (ret) {
25 case 0:
26 printf("No error found\n");
27 break;
28
29 case -1:
30 printf("Parameter error when attempting to get last error\n");
31 break;
32
33 default:
34 printf("libvirt reported: \"%s\"\n", err->message);
35 break;
36 }
37
38 virResetError(err);
39 free(err);
40 }
41
42
43 static int
showHypervisorInfo(virConnectPtr conn)44 showHypervisorInfo(virConnectPtr conn)
45 {
46 unsigned long hvVer, major, minor, release;
47 const char *hvType;
48
49 /* virConnectGetType returns a pointer to a static string, so no
50 * allocation or freeing is necessary; it is possible for the call
51 * to fail if, for example, there is no connection to a
52 * hypervisor, so check what it returns. */
53 hvType = virConnectGetType(conn);
54 if (hvType == NULL) {
55 printf("Failed to get hypervisor type\n");
56 showError(conn);
57 return 1;
58 }
59
60 if (virConnectGetVersion(conn, &hvVer) != 0) {
61 printf("Failed to get hypervisor version\n");
62 showError(conn);
63 return 1;
64 }
65
66 major = hvVer / 1000000;
67 hvVer %= 1000000;
68 minor = hvVer / 1000;
69 release = hvVer % 1000;
70
71 printf("Hypervisor: \"%s\" version: %lu.%lu.%lu\n",
72 hvType,
73 major,
74 minor,
75 release);
76
77 return 0;
78 }
79
80
81 static int
showDomains(virConnectPtr conn)82 showDomains(virConnectPtr conn)
83 {
84 int ret = 0, numNames, numInactiveDomains, numActiveDomains;
85 ssize_t i;
86 char **nameList = NULL;
87
88 numActiveDomains = virConnectNumOfDomains(conn);
89 if (numActiveDomains == -1) {
90 ret = 1;
91 printf("Failed to get number of active domains\n");
92 showError(conn);
93 goto out;
94 }
95
96 numInactiveDomains = virConnectNumOfDefinedDomains(conn);
97 if (numInactiveDomains == -1) {
98 ret = 1;
99 printf("Failed to get number of inactive domains\n");
100 showError(conn);
101 goto out;
102 }
103
104 printf("There are %d active and %d inactive domains\n",
105 numActiveDomains, numInactiveDomains);
106
107 nameList = malloc(sizeof(*nameList) * numInactiveDomains);
108
109 if (nameList == NULL) {
110 ret = 1;
111 printf("Could not allocate memory for list of inactive domains\n");
112 goto out;
113 }
114
115 numNames = virConnectListDefinedDomains(conn,
116 nameList,
117 numInactiveDomains);
118
119 if (numNames == -1) {
120 ret = 1;
121 printf("Could not get list of defined domains from hypervisor\n");
122 showError(conn);
123 goto out;
124 }
125
126 if (numNames > 0)
127 printf("Inactive domains:\n");
128
129 for (i = 0; i < numNames; i++) {
130 printf(" %s\n", *(nameList + i));
131 /* The API documentation doesn't say so, but the names
132 * returned by virConnectListDefinedDomains are strdup'd and
133 * must be freed here. */
134 free(*(nameList + i));
135 }
136
137 out:
138 free(nameList);
139 return ret;
140 }
141
142 /* Struct to pass the credentials to the auth callback via the cbdata pointer */
143 struct _AuthData {
144 char *username;
145 char *password;
146 };
147
148 typedef struct _AuthData AuthData;
149
150 /* This function will be called by libvirt to obtain credentials in order to
151 * authenticate to the hypervisor */
152 static int
authCallback(virConnectCredentialPtr cred,unsigned int ncred,void * cbdata)153 authCallback(virConnectCredentialPtr cred, unsigned int ncred, void *cbdata)
154 {
155 size_t i;
156 AuthData *authData = cbdata;
157
158 /* libvirt might request multiple credentials in a single call.
159 * This example supports VIR_CRED_AUTHNAME and VIR_CRED_PASSPHRASE
160 * credentials only, but there are several other types.
161 *
162 * A request may also contain a prompt message that can be displayed
163 * to the user and a challenge. The challenge is specific to the
164 * credential type and hypervisor type.
165 *
166 * For example the ESX driver passes the hostname of the ESX or vCenter
167 * server as challenge. This allows a auth callback to return the
168 * proper credentials. */
169 for (i = 0; i < ncred; ++i) {
170 switch (cred[i].type) {
171 case VIR_CRED_AUTHNAME:
172 cred[i].result = strdup(authData->username);
173
174 if (cred[i].result == NULL)
175 return -1;
176
177 cred[i].resultlen = strlen(cred[i].result);
178 break;
179
180 case VIR_CRED_PASSPHRASE:
181 cred[i].result = strdup(authData->password);
182
183 if (cred[i].result == NULL)
184 return -1;
185
186 cred[i].resultlen = strlen(cred[i].result);
187 break;
188
189 default:
190 return -1;
191 }
192 }
193
194 return 0;
195 }
196
197
198 /* The list of credential types supported by our auth callback */
199 static int credTypes[] = {
200 VIR_CRED_AUTHNAME,
201 VIR_CRED_PASSPHRASE
202 };
203
204
205 /* The auth struct that will be passed to virConnectOpenAuth */
206 static virConnectAuth auth = {
207 credTypes,
208 sizeof(credTypes) / sizeof(int),
209 authCallback,
210 NULL, /* cbdata will be initialized in main */
211 };
212
213
214 int
main(int argc,char * argv[])215 main(int argc, char *argv[])
216 {
217 int ret = 0;
218 virConnectPtr conn;
219 char *uri;
220 AuthData authData;
221
222 if (argc != 4) {
223 printf("Usage: %s <uri> <username> <password>\n", argv[0]);
224 return 1;
225 }
226
227 uri = argv[1];
228 authData.username = argv[2];
229 authData.password = argv[3];
230 auth.cbdata = &authData;
231
232 printf("Attempting to connect to hypervisor\n");
233
234 conn = virConnectOpenAuth(uri, &auth, 0);
235
236 if (NULL == conn) {
237 printf("No connection to hypervisor\n");
238 showError(conn);
239 return 1;
240 }
241
242 uri = virConnectGetURI(conn);
243 if (uri == NULL) {
244 ret = 1;
245 printf("Failed to get URI for hypervisor connection\n");
246 showError(conn);
247 goto disconnect;
248 }
249
250 printf("Connected to hypervisor at \"%s\"\n", uri);
251 free(uri);
252
253 if (showHypervisorInfo(conn) != 0) {
254 ret = 1;
255 goto disconnect;
256 }
257
258 if (showDomains(conn) != 0) {
259 ret = 1;
260 goto disconnect;
261 }
262
263 disconnect:
264 if (virConnectClose(conn) != 0) {
265 printf("Failed to disconnect from hypervisor\n");
266 showError(conn);
267 ret = 1;
268 } else {
269 printf("Disconnected from hypervisor\n");
270 }
271
272 return ret;
273 }
274