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