This is the 2nd iteration of my remote authentication / SASL patches previously provided here: http://www.redhat.com/archives/libvir-list/2007-October/msg00131.html In this iteration I've changed the wire protocol to give better compatability with older libvirt clients. My previous version clients would get a cryptic "unknown status 3" if the server was mandating authentication. This is because I extended the reply codes for RPC to include a specific 'auth required' code which old clients are not expecting. The idea was that the new client would run the REMOTE_PROC_OPEN rpc call & it would return a special NEED_AUTH code, the client would then authenticate & redo the REMOTE_PROC_OPEN. In the new way of doing things, instead of calling REMOTE_PROC_OPEN as the first RPC, a new client will do REMOTE_PROC_AUTH_LIST to query auth types required by the server. It will choose an auth method (there may be several to choose from), then complete the auth sequence. Only then will it try to do the REMOTE_PROC_OPEN. For compatability with older servers which do not implement the REMOTE_PROC_AUTH_LIST rpc, it will catch & ignore the error this may generate. Old clients which don't know to call REMOTE_PROC_AUTH_LIST will get a proper virErrorPtr object returned from REMOTE_PROC_OPEN with a clear 'authentication required' message. The end result is that new client <-> new server has same level of functionality as my previous patches, and old client <-> new server gets friendly errors reported (if server mandates auth - if no auth is enabled old client works just fine). The main outstanding item to be finalized before these patches can be added to CVS is the question of callbacks. For some auth methods we need to be able to gather credentials from the user. There is no way for the caller to know ahead of time what credentials are needed, because this is deterined by the config of the server. Thus we need callbacks in some form. I've come up with a couple of ideas... 1. A global method to supply a list of callbacks per credential type: enum { VIR_CONN_AUTH_PASSWORD, VIR_CONN_AUTH_USERNAME, VIR_CONN_AUTH_LANG, VIR_CONN_AUTH_CHALLENGE, VIR_CONN_AUTH_REALM, } virConnectAuthToken; typedef int (virConnectAuthCBSimple)(const char **result, unsigned *len); typedef int (virConnectAuthCBPrompt)(const char *challenge, const char *prompt, const char *defresult, const char *result, unsigned *len); typedef int (virConnetAuthCBRealm)(const char **availrealms, const char *result); typedef struct { int token; union { virConnectAuthCBSimple simple; virConnectAuthCBPrompt prompt; virConnectAuthCBRealm realm; } cb; } virConnectAuthCallback; virConnectSetAuthCallbacks(virConnectAuthCallback *cbs, int ncbs) This is described a little more here: http://www.redhat.com/archives/libvir-list/2007-January/msg00024.html 2. A new variant of virConnectOpen which takes a callback. The callback gives invoked with a list of required credentials struct _virConnectInteract { int type; /* One of virConnectInteractType constants */ const char *prompt; const char *challenge; const char *defresult; char *result; unsigned int resultlen; }; typedef struct _virConnectInteract virConnectInteract; typedef virConnectInteract *virConnectInteractPtr; /** * When authentication requires one or more interactions, this callback * is invoked. For each interaction supplied, data must be gathered * from the user and filled in to the 'result' and 'resultlen' fields. * If an interaction can not be filled, fill in NULL and 0. * * Return 0 if all interactions were filled, or -1 upon error */ typedef int (*virConnectAuthCallbackPtr)(const char *uri, virConnectInteractPtr interact, unsigned int ninteract); virConnectPtr virConnectOpenAuth (const char *name, virConnectAuthCallbackPtr cb, int flags); Iternally the virConnectOpen & virConnectOpenReadOnly can both just be delegating to this new virConnectOpenAuth call. Existing users of libvirt won't know about this new call, but that doesn't matter because they're not loosing any functionality - merely not able to put up UI to prompt for auth credentials/ The compelling thing about the 2nd way of doing things is that the callback gets a complete list of all required data items at once. This makes it very easy to present a UI with form entry fields for all items. The first way where there is a separate callback per item makes UI very hard. There is one issue not addressed by those two options though - there may be a choice of authentication methods to use. eg SASL vs PolicyKit. The callback only provides a way to supply credentials, no way to choose between auth types if a server offers more than one. Again there's a couple of ways to address this. 1. A global method to set preferred auth type. Simply a sorted list of auth types. Internally, we pick the first auth type in this list that the server supports virConnectSetAuthPriority(int types[], int ntypes); 2. A 2nd callback providing the int types[] and letting the client app choose which one they want to use per connection. 3. Separate out the operation of creating a virConnectPtr object, from the act of connecting, eg /* Allocate a handle */ virConnectPtr virConnectNew(const char *uri); /* List available auth methods */ int virConnectListAuth(virConnectPtr conn, int **types, int *ntypes); /* Connect to HV, with a speciifc auth method */ int virConnectInit(virConnectPtr conn, int auth); Any of these three, can be combined with either of the 2 options for supplying auth credentials. So we've got a choice of 6 :-) My preference, is to go for option 2, of the credentials choice, and option 1 of the auth type priority choice. eg a static priority list for auth types, and a single callback passed into a new virConnectOpenAuth() call. The final tedious bit, is the question of how we deal with underlying HV which may need further authentication. eg, if connecting to XenAPI we may need to provide a username & password. If the XenAPI connection is being made through a local libvirt driver hooking up the callbacks as described is fairly easy. If the XenAPI connection is made indirectly via the remote driver, then we have two drivers requiring auth - the initial remote driver, and then the remotely run XenAPi driver. This would need us to figure out a way to hook up the callbacks to the REMOTE_PROC_OPEN api call. Not pleasant ! Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list