r23794: convert more code from LGPLv2+ to LGPLv3+
[kai/samba-autobuild/.git] / source3 / nsswitch / wb_client.c
index 142c61d9c1ccaa051ffea2b6c34637cd1fb815c6..46caa1087c8828da29fc8b9cb66fc4b7ff3ff15d 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 2.0
+   Unix SMB/CIFS implementation.
 
    winbind client code
 
    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.
+   version 3 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.   
+   You should have received a copy of the GNU Library General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "nsswitch/winbind_nss.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+NSS_STATUS winbindd_request_response(int req_type,
+                                 struct winbindd_request *request,
+                                 struct winbindd_response *response);
 
 /* Call winbindd to convert a name to a sid */
 
-BOOL winbind_lookup_name(char *name, DOM_SID *sid, enum SID_NAME_USE *name_type)
+BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid, 
+                         enum lsa_SidType *name_type)
 {
        struct winbindd_request request;
        struct winbindd_response response;
-       enum nss_status result;
+       NSS_STATUS result;
        
        if (!sid || !name_type)
                return False;
@@ -41,11 +47,14 @@ BOOL winbind_lookup_name(char *name, DOM_SID *sid, enum SID_NAME_USE *name_type)
        ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       fstrcpy(request.data.name, name);
-       if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
+       fstrcpy(request.data.name.dom_name, dom_name);
+       fstrcpy(request.data.name.name, name);
+
+       if ((result = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, 
                                       &response)) == NSS_STATUS_SUCCESS) {
-               string_to_sid(sid, response.data.sid.sid);
-               *name_type = (enum SID_NAME_USE)response.data.sid.type;
+               if (!string_to_sid(sid, response.data.sid.sid))
+                       return False;
+               *name_type = (enum lsa_SidType)response.data.sid.type;
        }
 
        return result == NSS_STATUS_SUCCESS;
@@ -53,39 +62,173 @@ BOOL winbind_lookup_name(char *name, DOM_SID *sid, enum SID_NAME_USE *name_type)
 
 /* Call winbindd to convert sid to name */
 
-BOOL winbind_lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
+BOOL winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, 
+                       const char **domain, const char **name,
+                        enum lsa_SidType *name_type)
 {
        struct winbindd_request request;
        struct winbindd_response response;
-       enum nss_status result;
-       fstring sid_str;
+       NSS_STATUS result;
        
        /* Initialise request */
 
        ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       sid_to_string(sid_str, sid);
-       fstrcpy(request.data.sid, sid_str);
+       fstrcpy(request.data.sid, sid_string_static(sid));
        
        /* Make request */
 
-       result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
+       result = winbindd_request_response(WINBINDD_LOOKUPSID, &request,
+                                          &response);
+
+       if (result != NSS_STATUS_SUCCESS) {
+               return False;
+       }
 
        /* Copy out result */
 
-       if (result == NSS_STATUS_SUCCESS) {
-               parse_domain_user(response.data.name.name, dom_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 ));
+       if (domain != NULL) {
+               *domain = talloc_strdup(mem_ctx, response.data.name.dom_name);
+               if (*domain == NULL) {
+                       DEBUG(0, ("talloc failed\n"));
+                       return False;
+               }
+       }
+       if (name != NULL) {
+               *name = talloc_strdup(mem_ctx, response.data.name.name);
+               if (*name == NULL) {
+                       DEBUG(0, ("talloc failed\n"));
+                       return False;
+               }
        }
 
-       return (result == NSS_STATUS_SUCCESS);
+       *name_type = (enum lsa_SidType)response.data.name.type;
+
+       DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
+                  sid_string_static(sid), response.data.name.dom_name,
+                  response.data.name.name));
+       return True;
+}
+
+BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
+                        const DOM_SID *domain_sid,
+                        int num_rids, uint32 *rids,
+                        const char **domain_name,
+                        const char ***names, enum lsa_SidType **types)
+{
+       size_t i, buflen;
+       ssize_t len;
+       char *ridlist;
+       char *p;
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+
+       if (num_rids == 0) {
+               return False;
+       }
+
+       /* Initialise request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.sid, sid_string_static(domain_sid));
+       
+       len = 0;
+       buflen = 0;
+       ridlist = NULL;
+
+       for (i=0; i<num_rids; i++) {
+               sprintf_append(mem_ctx, &ridlist, &len, &buflen,
+                              "%ld\n", rids[i]);
+       }
+
+       if ((num_rids != 0) && (ridlist == NULL)) {
+               return False;
+       }
+
+       request.extra_data.data = ridlist;
+       request.extra_len = strlen(ridlist)+1;
+
+       result = winbindd_request_response(WINBINDD_LOOKUPRIDS,
+                                          &request, &response);
+
+       TALLOC_FREE(ridlist);
+
+       if (result != NSS_STATUS_SUCCESS) {
+               return False;
+       }
+
+       *domain_name = talloc_strdup(mem_ctx, response.data.domain_name);
+
+       if (num_rids) {
+               *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
+               *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+
+               if ((*names == NULL) || (*types == NULL)) {
+                       goto fail;
+               }
+       } else {
+               *names = NULL;
+               *types = NULL;
+       }
+
+       p = (char *)response.extra_data.data;
+
+       for (i=0; i<num_rids; i++) {
+               char *q;
+
+               if (*p == '\0') {
+                       DEBUG(10, ("Got invalid reply: %s\n",
+                                  (char *)response.extra_data.data));
+                       goto fail;
+               }
+                       
+               (*types)[i] = (enum lsa_SidType)strtoul(p, &q, 10);
+
+               if (*q != ' ') {
+                       DEBUG(10, ("Got invalid reply: %s\n",
+                                  (char *)response.extra_data.data));
+                       goto fail;
+               }
+
+               p = q+1;
+
+               q = strchr(p, '\n');
+               if (q == NULL) {
+                       DEBUG(10, ("Got invalid reply: %s\n",
+                                  (char *)response.extra_data.data));
+                       goto fail;
+               }
+
+               *q = '\0';
+
+               (*names)[i] = talloc_strdup(*names, p);
+
+               p = q+1;
+       }
+
+       if (*p != '\0') {
+               DEBUG(10, ("Got invalid reply: %s\n",
+                          (char *)response.extra_data.data));
+               goto fail;
+       }
+
+       SAFE_FREE(response.extra_data.data);
+
+       return True;
+
+ fail:
+       TALLOC_FREE(*names);
+       TALLOC_FREE(*types);
+       return False;
 }
 
 /* Call winbindd to convert SID to uid */
 
-BOOL winbind_sid_to_uid(uid_t *puid, DOM_SID *sid)
+BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
 {
        struct winbindd_request request;
        struct winbindd_response response;
@@ -105,7 +248,7 @@ BOOL winbind_sid_to_uid(uid_t *puid, DOM_SID *sid)
        
        /* Make request */
 
-       result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
+       result = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
 
        /* Copy out result */
 
@@ -136,12 +279,13 @@ BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
 
        /* Make request */
 
-       result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
+       result = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
 
        /* Copy out result */
 
        if (result == NSS_STATUS_SUCCESS) {
-               string_to_sid(sid, response.data.sid.sid);
+               if (!string_to_sid(sid, response.data.sid.sid))
+                       return False;
        } else {
                sid_copy(sid, &global_sid_NULL);
        }
@@ -151,7 +295,7 @@ BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
 
 /* Call winbindd to convert SID to gid */
 
-BOOL winbind_sid_to_gid(gid_t *pgid, DOM_SID *sid)
+BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
 {
        struct winbindd_request request;
        struct winbindd_response response;
@@ -171,7 +315,7 @@ BOOL winbind_sid_to_gid(gid_t *pgid, DOM_SID *sid)
        
        /* Make request */
 
-       result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
+       result = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
 
        /* Copy out result */
 
@@ -202,12 +346,13 @@ BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
 
        /* Make request */
 
-       result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
+       result = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
 
        /* Copy out result */
 
        if (result == NSS_STATUS_SUCCESS) {
-               string_to_sid(sid, response.data.sid.sid);
+               if (!string_to_sid(sid, response.data.sid.sid))
+                       return False;
        } else {
                sid_copy(sid, &global_sid_NULL);
        }
@@ -215,217 +360,230 @@ BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
        return (result == NSS_STATUS_SUCCESS);
 }
 
-/* Fetch the list of groups a user is a member of from winbindd.  This is
-   used by winbind_initgroups and winbind_getgroups. */
+/* Call winbindd to convert SID to uid */
 
-static int wb_getgroups(char *user, gid_t **groups)
+BOOL winbind_sids_to_unixids(struct id_map *ids, int num_ids)
 {
        struct winbindd_request request;
        struct winbindd_response response;
        int result;
+       DOM_SID *sids;
+       int i;
 
-       /* Call winbindd */
-
-       fstrcpy(request.data.username, user);
+       /* Initialise request */
 
+       ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+       request.extra_len = num_ids * sizeof(DOM_SID);
+
+       sids = (DOM_SID *)SMB_MALLOC(request.extra_len);
+       for (i = 0; i < num_ids; i++) {
+               sid_copy(&sids[i], ids[i].sid);
+       }
+
+       request.extra_data.data = (char *)sids;
+       
+       /* Make request */
+
+       result = winbindd_request_response(WINBINDD_SIDS_TO_XIDS, &request, &response);
+
+       /* Copy out result */
 
        if (result == NSS_STATUS_SUCCESS) {
+               struct unixid *wid = (struct unixid *)response.extra_data.data;
                
-               /* Return group list.  Don't forget to free the group list
-                  when finished. */
-
-               *groups = (gid_t *)response.extra_data;
-               return response.data.num_entries;
+               for (i = 0; i < num_ids; i++) {
+                       if (wid[i].type == -1) {
+                               ids[i].status = ID_UNMAPPED;
+                       } else {
+                               ids[i].status = ID_MAPPED;
+                               ids[i].xid.type = wid[i].type;
+                               ids[i].xid.id = wid[i].id;
+                       }
+               }
        }
 
-       return -1;
-}
+       SAFE_FREE(request.extra_data.data);
+       SAFE_FREE(response.extra_data.data);
 
-/* 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. */
+       return (result == NSS_STATUS_SUCCESS);
+}
 
-int winbind_initgroups(char *user, gid_t gid)
+BOOL winbind_idmap_dump_maps(TALLOC_CTX *memctx, const char *file)
 {
-       gid_t *groups = NULL;
+       struct winbindd_request request;
+       struct winbindd_response response;
        int result;
-       char *sep;
 
-       /* Call normal initgroups if we are a local user */
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-       sep = lp_winbind_separator();
+       request.extra_data.data = SMB_STRDUP(file);
+       request.extra_len = strlen(request.extra_data.data) + 1;
 
-       if (!strchr(user, *sep)) {
-               return initgroups(user, gid);
-       }
+       result = winbindd_request_response(WINBINDD_DUMP_MAPS, &request, &response);
 
-       result = wb_getgroups(user, &groups);
+       SAFE_FREE(request.extra_data.data);
+       return (result == NSS_STATUS_SUCCESS);
+}
 
-       DEBUG(10,("wb_getgroups: %s: result = %s\n", user, result == -1 ?
-                 "FAIL" : "SUCCESS"));
+BOOL winbind_allocate_uid(uid_t *uid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
 
-       if (result != -1) {
-               int ngroups = result, i;
-               BOOL is_member = False;
+       /* Initialise request */
 
-               /* Check to see if the passed gid is already in the list */
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-               for (i = 0; i < ngroups; i++) {
-                       if (groups[i] == gid) {
-                               is_member = True;
-                       }
-               }
+       /* Make request */
 
-               /* Add group to list if necessary */
+       result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
+                                          &request, &response);
 
-               if (!is_member) {
-                       groups = Realloc(groups, sizeof(gid_t) * ngroups + 1);
-                       
-                       if (!groups) {
-                               errno = ENOMEM;
-                               result = -1;
-                               goto done;
-                       }
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
 
-                       groups[ngroups] = gid;
-                       ngroups++;
-               }
+       /* Copy out result */
+       *uid = response.data.uid;
 
-               /* Set the groups */
+       return True;
+}
 
-               if (sys_setgroups(ngroups, groups) == -1) {
-                       errno = EPERM;
-                       result = -1;
-                       goto done;
-               }
-       }
+BOOL winbind_allocate_gid(gid_t *gid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
 
-       /* Free response data if necessary */
+       /* Initialise request */
 
- done:
-       safe_free(groups);
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-       return result;
-}
+       /* Make request */
 
-/* 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. */
+       result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
+                                          &request, &response);
 
-int winbind_getgroups(char *user, int size, gid_t *list)
-{
-       gid_t *groups = NULL;
-       int result, i;
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
 
-       /* Fetch list of groups */
+       /* Copy out result */
+       *gid = response.data.gid;
 
-       result = wb_getgroups(user, &groups);
+       return True;
+}
 
-       if (size == 0) goto done;
+BOOL winbind_set_mapping(const struct id_map *map)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
 
-       if (result > size) {
-               result = -1;
-               errno = EINVAL; /* This is what getgroups() does */
-               goto done;
-       }
+       /* Initialise request */
 
-       /* Copy list of groups across */
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-       for (i = 0; i < result; i++) {
-               list[i] = groups[i];
-       }
+       /* Make request */
 
- done:
-       safe_free(groups);
-       return result;
-}
+       request.data.dual_idmapset.id = map->xid.id;
+       request.data.dual_idmapset.type = map->xid.type;
+       sid_to_string(request.data.dual_idmapset.sid, map->sid);
+
+       result = winbindd_request_response(WINBINDD_SET_MAPPING, &request, &response);
 
-/**********************************************************************************
- Utility function. Convert a uid_t to a name if possible.
-**********************************************************************************/
+       return (result == NSS_STATUS_SUCCESS);
+}
 
-BOOL winbind_uidtoname(fstring name, uid_t uid)
+BOOL winbind_set_uid_hwm(unsigned long id)
 {
-       DOM_SID sid;
-       fstring dom_name;
-       fstring user_name;
-       enum SID_NAME_USE name_type;
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
 
-       if (!winbind_uid_to_sid(&sid, uid))
-               return False;
-       if (!winbind_lookup_sid(&sid, dom_name, user_name, &name_type))
-               return False;
+       /* Initialise request */
 
-       if (name_type != SID_NAME_USER)
-               return False;
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-       slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, lp_winbind_separator(), user_name );
-       return True;
-}
+       /* Make request */
 
-/**********************************************************************************
- Utility function. Convert a gid_t to a name if possible.
-**********************************************************************************/
+       request.data.dual_idmapset.id = id;
+       request.data.dual_idmapset.type = ID_TYPE_UID;
 
-BOOL winbind_gidtoname(fstring name, gid_t gid)
+       result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
+
+       return (result == NSS_STATUS_SUCCESS);
+}
+
+BOOL winbind_set_gid_hwm(unsigned long id)
 {
-       DOM_SID sid;
-       fstring dom_name;
-       fstring group_name;
-       enum SID_NAME_USE name_type;
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
 
-       if (!winbind_gid_to_sid(&sid, gid))
-               return False;
-       if (!winbind_lookup_sid(&sid, dom_name, group_name, &name_type))
-               return False;
+       /* Initialise request */
 
-       if (name_type != SID_NAME_USER)
-               return False;
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-       slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, lp_winbind_separator(), group_name );
-       return True;
+       /* Make request */
+
+       request.data.dual_idmapset.id = id;
+       request.data.dual_idmapset.type = ID_TYPE_GID;
+
+       result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
+
+       return (result == NSS_STATUS_SUCCESS);
 }
 
-/**********************************************************************************
- Utility function. Convert a name to a uid_t if possible.
-**********************************************************************************/
+/**********************************************************************
+ simple wrapper function to see if winbindd is alive
+**********************************************************************/
 
-BOOL winbind_nametouid(uid_t *puid, char *name)
+BOOL winbind_ping( void )
 {
-       DOM_SID sid;
-       enum SID_NAME_USE name_type;
-
-       if (!winbind_lookup_name(name, &sid, &name_type)) {
-        return False;
-    }
+       NSS_STATUS result;
 
-       if (name_type != SID_NAME_USER)
-               return False;
+       result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
 
-       return winbind_sid_to_uid(puid, &sid);
+       return result == NSS_STATUS_SUCCESS;
 }
 
-/**********************************************************************************
- Utility function. Convert a name to a gid_t if possible.
-**********************************************************************************/
+/**********************************************************************
+ Is a domain trusted?
+
+ result == NSS_STATUS_UNAVAIL: winbind not around
+ result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
 
-BOOL winbind_nametogid(gid_t *pgid, char *gname)
+ Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off and
+ when winbind return WINBINDD_ERROR. So the semantics of this routine depends
+ on winbind_on. Grepping for winbind_off I just found 3 places where winbind
+ is turned off, and this does not conflict (as far as I have seen) with the
+ callers of is_trusted_domains.
+
+ I *hate* global variables....
+
+ Volker
+
+**********************************************************************/
+
+NSS_STATUS wb_is_trusted_domain(const char *domain)
 {
-       DOM_SID g_sid;
-       enum SID_NAME_USE name_type;
+       struct winbindd_request request;
+       struct winbindd_response response;
 
-       if (!winbind_lookup_name(gname, &g_sid, &name_type)) {
-        return False;
-    }
+       /* Call winbindd */
 
-       if (name_type != SID_NAME_DOM_GRP)
-               return False;
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.domain_name, domain);
 
-       return winbind_sid_to_gid(pgid, &g_sid);
+       return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);
 }