r23794: convert more code from LGPLv2+ to LGPLv3+
[kai/samba-autobuild/.git] / source3 / nsswitch / wb_client.c
index 53550ca353d4c5b9c739c2f3379d893e93a44d9e..46caa1087c8828da29fc8b9cb66fc4b7ff3ff15d 100644 (file)
@@ -9,30 +9,31 @@
    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/nss.h"
+#include "nsswitch/winbind_nss.h"
 
-NSS_STATUS winbindd_request(int req_type,
+#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(const char *dom_name, const char *name, DOM_SID *sid, 
-                         enum SID_NAME_USE *name_type)
+                         enum lsa_SidType *name_type)
 {
        struct winbindd_request request;
        struct winbindd_response response;
@@ -49,10 +50,11 @@ BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
        fstrcpy(request.data.name.dom_name, dom_name);
        fstrcpy(request.data.name.name, name);
 
-       if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
+       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;
@@ -60,44 +62,173 @@ BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
 
 /* 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;
        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);
+       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) {
-               fstrcpy(dom_name, response.data.name.dom_name);
-               fstrcpy(name, response.data.name.name);
-               *name_type = (enum SID_NAME_USE)response.data.name.type;
+       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;
+               }
+       }
+
+       *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;
 
-               DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
-                           sid_str, dom_name, name));
+       if (num_rids == 0) {
+               return False;
        }
 
-       return (result == NSS_STATUS_SUCCESS);
+       /* 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;
@@ -117,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 */
 
@@ -148,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);
        }
@@ -163,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;
@@ -183,7 +315,7 @@ BOOL winbind_sid_to_gid(gid_t *pgid, DOM_SID *sid)
        
        /* Make request */
 
-       result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
+       result = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
 
        /* Copy out result */
 
@@ -214,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);
        }
@@ -227,73 +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_getgroups. */
+/* Call winbindd to convert SID to uid */
 
-static int wb_getgroups(const 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);
+
+       return (result == NSS_STATUS_SUCCESS);
 }
 
-/* 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. */
+BOOL winbind_idmap_dump_maps(TALLOC_CTX *memctx, const char *file)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       request.extra_data.data = SMB_STRDUP(file);
+       request.extra_len = strlen(request.extra_data.data) + 1;
 
-int winbind_getgroups(const char *user, int size, gid_t *list)
+       result = winbindd_request_response(WINBINDD_DUMP_MAPS, &request, &response);
+
+       SAFE_FREE(request.extra_data.data);
+       return (result == NSS_STATUS_SUCCESS);
+}
+
+BOOL winbind_allocate_uid(uid_t *uid)
 {
-       gid_t *groups = NULL;
-       int result, i;
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
 
-       /*
-        * Don't do the lookup if the name has no separator _and_ we are not in
-        * 'winbind use default domain' mode.
-        */
+       /* Initialise request */
 
-       if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
-               return -1;
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
 
-       /* Fetch list of groups */
+       /* Make request */
 
-       result = wb_getgroups(user, &groups);
+       result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
+                                          &request, &response);
 
-       if (size == 0)
-               goto done;
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
 
-       if (result > size) {
-               result = -1;
-               errno = EINVAL; /* This is what getgroups() does */
-               goto done;
-       }
+       /* Copy out result */
+       *uid = response.data.uid;
 
-       /* Copy list of groups across */
+       return True;
+}
 
-       for (i = 0; i < result; i++) {
-               list[i] = groups[i];
-       }
+BOOL winbind_allocate_gid(gid_t *gid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
+
+       /* Initialise request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Make request */
+
+       result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
+                                          &request, &response);
+
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+
+       /* Copy out result */
+       *gid = response.data.gid;
+
+       return True;
+}
+
+BOOL winbind_set_mapping(const struct id_map *map)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
+
+       /* Initialise request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Make request */
+
+       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);
+
+       return (result == NSS_STATUS_SUCCESS);
+}
+
+BOOL winbind_set_uid_hwm(unsigned long id)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
+
+       /* Initialise request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Make request */
+
+       request.data.dual_idmapset.id = id;
+       request.data.dual_idmapset.type = ID_TYPE_UID;
+
+       result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
+
+       return (result == NSS_STATUS_SUCCESS);
+}
+
+BOOL winbind_set_gid_hwm(unsigned long id)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int result;
+
+       /* Initialise request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* 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);
+}
+
+/**********************************************************************
+ simple wrapper function to see if winbindd is alive
+**********************************************************************/
+
+BOOL winbind_ping( void )
+{
+       NSS_STATUS result;
+
+       result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
+
+       return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Is a domain trusted?
+
+ result == NSS_STATUS_UNAVAIL: winbind not around
+ result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
+
+ 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)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+
+       /* Call winbindd */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.domain_name, domain);
 
- done:
-       SAFE_FREE(groups);
-       return result;
+       return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);
 }