r25175: Change to talloc_asprintf_append_buffer().
[jelmer/samba4-debian.git] / source / winbind / wb_samba3_cmd.c
index 7989bec17223e2e2190bcad3c25548ebffe0cfa4..56a168ebb0ed65386a4a7bedca61ace7c2bca8ed 100644 (file)
@@ -8,7 +8,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "nsswitch/winbindd_nss.h"
 #include "winbind/wb_server.h"
 #include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
 #include "libcli/composite/composite.h"
 #include "version.h"
 #include "librpc/gen_ndr/netlogon.h"
 #include "libcli/security/security.h"
 #include "auth/pam_errors.h"
+#include "param/param.h"
 
 /* 
    Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
@@ -111,9 +111,9 @@ NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
 {
        s3call->response.result                 = WINBINDD_OK;
-       s3call->response.extra_data =
+       s3call->response.extra_data.data =
                smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
-       NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
+       NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data.data);
        return NT_STATUS_OK;
 }
 
@@ -252,7 +252,7 @@ static void userdomgroups_recv_groups(struct composite_context *ctx)
        }
 
        for (i=0; i<num_sids; i++) {
-               sids_string = talloc_asprintf_append(
+               sids_string = talloc_asprintf_append_buffer(
                        sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
        }
 
@@ -262,7 +262,7 @@ static void userdomgroups_recv_groups(struct composite_context *ctx)
        }
 
        s3call->response.result = WINBINDD_OK;
-       s3call->response.extra_data = sids_string;
+       s3call->response.extra_data.data = sids_string;
        s3call->response.length += strlen(sids_string)+1;
        s3call->response.data.num_entries = num_sids;
 
@@ -319,7 +319,7 @@ static void usersids_recv_sids(struct composite_context *ctx)
        }
 
        for (i=0; i<num_sids; i++) {
-               sids_string = talloc_asprintf_append(
+               sids_string = talloc_asprintf_append_buffer(
                        sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
                if (sids_string == NULL) {
                        status = NT_STATUS_NO_MEMORY;
@@ -328,7 +328,7 @@ static void usersids_recv_sids(struct composite_context *ctx)
        }
 
        s3call->response.result = WINBINDD_OK;
-       s3call->response.extra_data = sids_string;
+       s3call->response.extra_data.data = sids_string;
        s3call->response.length += strlen(sids_string);
        s3call->response.data.num_entries = num_sids;
 
@@ -510,7 +510,7 @@ static void pam_auth_crap_recv(struct composite_context *ctx)
        }
 
        if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
-               s3call->response.extra_data = info3.data;
+               s3call->response.extra_data.data = info3.data;
                s3call->response.length += info3.length;
        }
 
@@ -521,7 +521,7 @@ static void pam_auth_crap_recv(struct composite_context *ctx)
        }
        
        if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
-               s3call->response.extra_data = unix_username;
+               s3call->response.extra_data.data = unix_username;
                s3call->response.length += strlen(unix_username)+1;
        }
 
@@ -529,27 +529,6 @@ static void pam_auth_crap_recv(struct composite_context *ctx)
        wbsrv_samba3_async_auth_epilogue(status, s3call);
 }
 
-/* Helper function: Split a domain\\user string into it's parts,
- * because the client supplies it as one string */
-
-static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
-                                char **domain, char **user)
-{
-       char *p = strchr(domuser, *lp_winbind_separator());
-
-       if (p == NULL) {
-               *domain = talloc_strdup(mem_ctx, lp_workgroup());
-       } else {
-               *domain = talloc_strndup(mem_ctx, domuser,
-                                        PTR_DIFF(p, domuser));
-               domuser = p+1;
-       }
-
-       *user = talloc_strdup(mem_ctx, domuser);
-
-       return ((*domain != NULL) && (*user != NULL));
-}
-
 /* Plaintext authentication 
    
    This interface is used by ntlm_auth in it's 'basic' authentication
@@ -566,7 +545,7 @@ NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
                s3call->wbconn->listen_socket->service;
        char *user, *domain;
 
-       if (!samba3_parse_domuser(s3call, 
+       if (!wb_samba3_split_username(s3call,
                                 s3call->request.data.auth.user,
                                 &domain, &user)) {
                return NT_STATUS_NO_SUCH_USER;
@@ -641,7 +620,7 @@ static void list_trustdom_recv_doms(struct composite_context *ctx)
        }
 
        for (i=0; i<num_domains; i++) {
-               result = talloc_asprintf_append(
+               result = talloc_asprintf_append_buffer(
                        result, "%s\\%s\\%s",
                        domains[i]->name, domains[i]->name,
                        dom_sid_string(s3call, domains[i]->sid));
@@ -654,10 +633,441 @@ static void list_trustdom_recv_doms(struct composite_context *ctx)
 
        s3call->response.result = WINBINDD_OK;
        if (num_domains > 0) {
-               s3call->response.extra_data = result;
+               s3call->response.extra_data.data = result;
                s3call->response.length += strlen(result)+1;
        }
 
  done:
        wbsrv_samba3_async_epilogue(status, s3call);
 }
+
+
+/* List users */
+
+static void list_users_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_list_users(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service =
+               s3call->wbconn->listen_socket->service;
+
+       DEBUG(5, ("wbsrv_samba3_list_users called\n"));
+
+       ctx = wb_cmd_list_users_send(s3call, service,
+                       s3call->request.domain_name);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = list_users_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+}
+
+static void list_users_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       uint32_t extra_data_len;
+       char *extra_data;
+       NTSTATUS status;
+
+       DEBUG(5, ("list_users_recv called\n"));
+
+       status = wb_cmd_list_users_recv(ctx, s3call, &extra_data_len,
+                       &extra_data);
+
+       if (NT_STATUS_IS_OK(status)) {
+               s3call->response.extra_data.data = extra_data;
+               s3call->response.length += extra_data_len;
+       }
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/* NSS calls */
+
+static void getpwnam_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service =
+               s3call->wbconn->listen_socket->service;
+
+       DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
+
+       ctx = wb_cmd_getpwnam_send(s3call, service,
+                       s3call->request.data.username);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = getpwnam_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+}
+
+static void getpwnam_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+       struct winbindd_pw *pw;
+
+       DEBUG(5, ("getpwnam_recv called\n"));
+
+       status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
+       if(NT_STATUS_IS_OK(status))
+               s3call->response.data.pw = *pw;
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void getpwuid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+
+       DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
+
+       ctx = wb_cmd_getpwuid_send(s3call, service,
+                       s3call->request.data.uid);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = getpwuid_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+}
+
+static void getpwuid_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+       struct winbindd_pw *pw;
+
+       DEBUG(5, ("getpwuid_recv called\n"));
+
+       status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
+       if (NT_STATUS_IS_OK(status))
+               s3call->response.data.pw = *pw;
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void setpwent_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+
+       DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
+
+       ctx = wb_cmd_setpwent_send(s3call, service);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = setpwent_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+}
+
+static void setpwent_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+       struct wbsrv_pwent *pwent;
+
+       DEBUG(5, ("setpwent_recv called\n"));
+
+       status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
+       if (NT_STATUS_IS_OK(status)) {
+               s3call->wbconn->protocol_private_data = pwent;
+       }
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void getpwent_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+       struct wbsrv_pwent *pwent;
+
+       DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
+
+       NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
+
+       pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
+                       struct wbsrv_pwent);
+       NT_STATUS_HAVE_NO_MEMORY(pwent);
+
+       ctx = wb_cmd_getpwent_send(s3call, service, pwent,
+                       s3call->request.data.num_entries);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = getpwent_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+}
+
+static void getpwent_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+       struct winbindd_pw *pw;
+       uint32_t num_users;
+
+       DEBUG(5, ("getpwent_recv called\n"));
+
+       status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
+       if (NT_STATUS_IS_OK(status)) {
+               uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
+
+               s3call->response.data.num_entries = num_users;
+               s3call->response.extra_data.data = pw;
+               s3call->response.length += extra_len;
+       }
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
+{
+       struct wbsrv_pwent *pwent =
+               talloc_get_type(s3call->wbconn->protocol_private_data,
+                               struct wbsrv_pwent);
+       DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
+
+       talloc_free(pwent);
+
+       s3call->wbconn->protocol_private_data = NULL;
+       s3call->response.result = WINBINDD_OK;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
+{
+       DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
+       s3call->response.result = WINBINDD_ERROR;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
+{
+       DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
+       s3call->response.result = WINBINDD_ERROR;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
+{
+       DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
+       s3call->response.result = WINBINDD_ERROR;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
+{
+       DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
+       s3call->response.result = WINBINDD_OK;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
+{
+       DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
+       s3call->response.result = WINBINDD_ERROR;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
+{
+       DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
+       s3call->response.result = WINBINDD_OK;
+       return NT_STATUS_OK;
+}
+
+static void sid2uid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service =
+               s3call->wbconn->listen_socket->service;
+       struct dom_sid *sid;
+
+       DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
+
+       sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+       NT_STATUS_HAVE_NO_MEMORY(sid);
+
+       ctx = wb_sid2uid_send(s3call, service, sid);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = sid2uid_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+
+}
+
+static void sid2uid_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+
+       DEBUG(5, ("sid2uid_recv called\n"));
+
+       status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void sid2gid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service =
+               s3call->wbconn->listen_socket->service;
+       struct dom_sid *sid;
+
+       DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
+
+       sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+       NT_STATUS_HAVE_NO_MEMORY(sid);
+
+       ctx = wb_sid2gid_send(s3call, service, sid);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = sid2gid_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+
+}
+
+static void sid2gid_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+
+       DEBUG(5, ("sid2gid_recv called\n"));
+
+       status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void uid2sid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service =
+               s3call->wbconn->listen_socket->service;
+
+       DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
+
+       ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = uid2sid_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+
+}
+
+static void uid2sid_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+       struct dom_sid *sid;
+       char *sid_str;
+
+       DEBUG(5, ("uid2sid_recv called\n"));
+
+       status = wb_uid2sid_recv(ctx, s3call, &sid);
+       if(NT_STATUS_IS_OK(status)) {
+               sid_str = dom_sid_string(s3call, sid);
+
+               /* If the conversion failed, bail out with a failure. */
+               if (sid_str == NULL)
+                       wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
+
+               /* But we assume this worked, so we'll set the string. Work
+                * done. */
+               WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
+               s3call->response.data.sid.type = SID_NAME_USER;
+       }
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void gid2sid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
+{
+       struct composite_context *ctx;
+       struct wbsrv_service *service =
+               s3call->wbconn->listen_socket->service;
+
+       DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
+
+       ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->async.fn = gid2sid_recv;
+       ctx->async.private_data = s3call;
+       s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+       return NT_STATUS_OK;
+
+}
+
+static void gid2sid_recv(struct composite_context *ctx)
+{
+       struct wbsrv_samba3_call *s3call =
+               talloc_get_type(ctx->async.private_data,
+                               struct wbsrv_samba3_call);
+       NTSTATUS status;
+       struct dom_sid *sid;
+       char *sid_str;
+
+       DEBUG(5, ("gid2sid_recv called\n"));
+
+       status = wb_gid2sid_recv(ctx, s3call, &sid);
+       if(NT_STATUS_IS_OK(status)) {
+               sid_str = dom_sid_string(s3call, sid);
+
+               if (sid_str == NULL)
+                       wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
+
+               WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
+               s3call->response.data.sid.type = SID_NAME_DOMAIN;
+       }
+
+       wbsrv_samba3_async_epilogue(status, s3call);
+}
+