summaryrefslogtreecommitdiffstats
path: root/source/nsswitch/wb_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/nsswitch/wb_client.c')
-rw-r--r--source/nsswitch/wb_client.c693
1 files changed, 693 insertions, 0 deletions
diff --git a/source/nsswitch/wb_client.c b/source/nsswitch/wb_client.c
new file mode 100644
index 00000000000..32dfc8decac
--- /dev/null
+++ b/source/nsswitch/wb_client.c
@@ -0,0 +1,693 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ winbind client code
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "includes.h"
+#include "nsswitch/winbind_nss.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern DOM_SID global_sid_NULL; /* NULL sid */
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+/* Call winbindd to convert a name to a sid */
+
+BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
+ enum SID_NAME_USE *name_type)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if (!sid || !name_type)
+ return False;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.name.dom_name, dom_name);
+ fstrcpy(request.data.name.name, name);
+
+ if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request,
+ &response)) == NSS_STATUS_SUCCESS) {
+ if (!string_to_sid(sid, response.data.sid.sid))
+ return False;
+ *name_type = (enum SID_NAME_USE)response.data.sid.type;
+ }
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/* Call winbindd to convert sid to name */
+
+BOOL winbind_lookup_sid(const DOM_SID *sid,
+ fstring dom_name, fstring name,
+ enum SID_NAME_USE *name_type)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ fstring sid_str;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ fstrcpy(dom_name, response.data.name.dom_name);
+ fstrcpy(name, response.data.name.name);
+ *name_type = (enum SID_NAME_USE)response.data.name.type;
+
+ DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n",
+ sid_str, dom_name, name));
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert SID to uid */
+
+BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+ fstring sid_str;
+
+ if (!puid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ *puid = response.data.uid;
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert uid to sid */
+
+BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ if (!sid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = uid;
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ if (!string_to_sid(sid, response.data.sid.sid))
+ return False;
+ } else {
+ sid_copy(sid, &global_sid_NULL);
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert SID to gid */
+
+BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+ fstring sid_str;
+
+ if (!pgid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ *pgid = response.data.gid;
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert gid to sid */
+
+BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ if (!sid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = gid;
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ if (!string_to_sid(sid, response.data.sid.sid))
+ return False;
+ } else {
+ sid_copy(sid, &global_sid_NULL);
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+BOOL winbind_allocate_rid(uint32 *rid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_ALLOCATE_RID, &request, &response);
+
+ if (result != NSS_STATUS_SUCCESS)
+ return False;
+
+ /* Copy out result */
+ *rid = response.data.rid;
+
+ return True;
+}
+
+/* Fetch the list of groups a user is a member of from winbindd. This is
+ used by winbind_getgroups. */
+
+static int wb_getgroups(const char *user, gid_t **groups)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ /* Call winbindd */
+
+ fstrcpy(request.data.username, user);
+
+ ZERO_STRUCT(response);
+
+ result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+
+ if (result == NSS_STATUS_SUCCESS) {
+
+ /* Return group list. Don't forget to free the group list
+ when finished. */
+
+ *groups = (gid_t *)response.extra_data;
+ return response.data.num_entries;
+ }
+
+ return -1;
+}
+
+/* Call winbindd to initialise group membership. This is necessary for
+ some systems (i.e RH5.2) that do not have an initgroups function as part
+ of the nss extension. In RH5.2 this is implemented using getgrent()
+ which can be amazingly inefficient as well as having problems with
+ username case. */
+
+int winbind_initgroups(char *user, gid_t gid)
+{
+ gid_t *tgr, *groups = NULL;
+ int result;
+
+ /* Call normal initgroups if we are a local user */
+
+ if (!strchr(user, *lp_winbind_separator())) {
+ return initgroups(user, gid);
+ }
+
+ result = wb_getgroups(user, &groups);
+
+ DEBUG(10,("winbind_getgroups: %s: result = %s\n", user,
+ result == -1 ? "FAIL" : "SUCCESS"));
+
+ if (result != -1) {
+ int ngroups = result, i;
+ BOOL is_member = False;
+
+ /* Check to see if the passed gid is already in the list */
+
+ for (i = 0; i < ngroups; i++) {
+ if (groups[i] == gid) {
+ is_member = True;
+ }
+ }
+
+ /* Add group to list if necessary */
+
+ if (!is_member) {
+ tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
+
+ if (!tgr) {
+ errno = ENOMEM;
+ result = -1;
+ goto done;
+ }
+ else groups = tgr;
+
+ groups[ngroups] = gid;
+ ngroups++;
+ }
+
+ /* Set the groups */
+
+ if (sys_setgroups(ngroups, groups) == -1) {
+ errno = EPERM;
+ result = -1;
+ goto done;
+ }
+
+ } else {
+
+ /* The call failed. Set errno to something so we don't get
+ a bogus value from the last failed system call. */
+
+ errno = EIO;
+ }
+
+ /* Free response data if necessary */
+
+ done:
+ SAFE_FREE(groups);
+
+ return result;
+}
+
+/* Return a list of groups the user is a member of. This function is
+ useful for large systems where inverting the group database would be too
+ time consuming. If size is zero, list is not modified and the total
+ number of groups for the user is returned. */
+
+int winbind_getgroups(const char *user, gid_t **list)
+{
+ /*
+ * Don't do the lookup if the name has no separator _and_ we are not in
+ * 'winbind use default domain' mode.
+ */
+
+ if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
+ return -1;
+
+ /* Fetch list of groups */
+
+ return wb_getgroups(user, list);
+}
+
+/**********************************************************************
+ simple wrapper function to see if winbindd is alive
+**********************************************************************/
+
+BOOL winbind_ping( void )
+{
+ NSS_STATUS result;
+
+ result = winbindd_request(WINBINDD_PING, NULL, NULL);
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to create a local user
+**********************************************************************/
+
+BOOL winbind_create_user( const char *name, uint32 *rid )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !name )
+ return False;
+
+ DEBUG(10,("winbind_create_user: %s\n", name));
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* see if the caller wants a new RID returned */
+
+ if ( rid )
+ request.flags = WBFLAG_ALLOCATE_RID;
+
+ fstrcpy( request.data.acct_mgt.username, name );
+ fstrcpy( request.data.acct_mgt.groupname, "" );
+
+ result = winbindd_request( WINBINDD_CREATE_USER, &request, &response);
+
+ if ( rid )
+ *rid = response.data.rid;
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to create a local group
+**********************************************************************/
+
+BOOL winbind_create_group( const char *name, uint32 *rid )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !name )
+ return False;
+
+ DEBUG(10,("winbind_create_group: %s\n", name));
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* see if the caller wants a new RID returned */
+
+ if ( rid )
+ request.flags = WBFLAG_ALLOCATE_RID;
+
+ fstrcpy( request.data.acct_mgt.groupname, name );
+
+
+ result = winbindd_request( WINBINDD_CREATE_GROUP, &request, &response);
+
+ if ( rid )
+ *rid = response.data.rid;
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to add a user to a local group
+**********************************************************************/
+
+BOOL winbind_add_user_to_group( const char *user, const char *group )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !user || !group )
+ return False;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ DEBUG(10,("winbind_add_user_to_group: user(%s), group(%s) \n",
+ user, group));
+
+ fstrcpy( request.data.acct_mgt.username, user );
+ fstrcpy( request.data.acct_mgt.groupname, group );
+
+ result = winbindd_request( WINBINDD_ADD_USER_TO_GROUP, &request, &response);
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to remove a user to a local group
+**********************************************************************/
+
+BOOL winbind_remove_user_from_group( const char *user, const char *group )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !user || !group )
+ return False;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ DEBUG(10,("winbind_remove_user_from_group: user(%s), group(%s) \n",
+ user, group));
+
+ ZERO_STRUCT(response);
+
+ fstrcpy( request.data.acct_mgt.username, user );
+ fstrcpy( request.data.acct_mgt.groupname, group );
+
+ result = winbindd_request( WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response);
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to set the primary group for a user local user
+**********************************************************************/
+
+BOOL winbind_set_user_primary_group( const char *user, const char *group )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !user || !group )
+ return False;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ DEBUG(10,("winbind_set_user_primary_group: user(%s), group(%s) \n",
+ user, group));
+
+ fstrcpy( request.data.acct_mgt.username, user );
+ fstrcpy( request.data.acct_mgt.groupname, group );
+
+ result = winbindd_request( WINBINDD_SET_USER_PRIMARY_GROUP, &request, &response);
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+ Ask winbindd to remove a user from its lists of accounts
+**********************************************************************/
+
+BOOL winbind_delete_user( const char *user )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !user )
+ return False;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ DEBUG(10,("winbind_delete_user: user (%s)\n", user));
+
+ fstrcpy( request.data.acct_mgt.username, user );
+
+ result = winbindd_request( WINBINDD_DELETE_USER, &request, &response);
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to remove a group from its lists of accounts
+**********************************************************************/
+
+BOOL winbind_delete_group( const char *group )
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if ( !lp_winbind_enable_local_accounts() )
+ return False;
+
+ if ( !group )
+ return False;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ DEBUG(10,("winbind_delete_group: group (%s)\n", group));
+
+ fstrcpy( request.data.acct_mgt.groupname, group );
+
+ result = winbindd_request( WINBINDD_DELETE_GROUP, &request, &response);
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/***********************************************************************/
+/* Call winbindd to convert SID to uid. Do not allocate */
+
+BOOL winbind_sid_to_uid_query(uid_t *puid, const DOM_SID *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+ fstring sid_str;
+
+ if (!puid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ request.flags = WBFLAG_QUERY_ONLY;
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ *puid = response.data.uid;
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert SID to gid. Do not allocate */
+
+BOOL winbind_sid_to_gid_query(gid_t *pgid, const DOM_SID *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+ fstring sid_str;
+
+ if (!pgid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ request.flags = WBFLAG_QUERY_ONLY;
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ *pgid = response.data.gid;
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/***********************************************************************/
+