]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
winbind:varlink: Implement get user record by name and uid
authorSamuel Cabrero <scabrero@samba.org>
Mon, 6 Feb 2023 17:24:15 +0000 (18:24 +0100)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 20 Feb 2025 08:07:32 +0000 (08:07 +0000)
$> varlink call unix:/run/systemd/userdb/org.samba.winbind/io.systemd.UserDatabase.GetUserRecord "{\"service\":\"org.samba.winbind\",\"userName\":\"AFOREST+user1\",\"uid\":21105}"
{
  "incomplete": false,
  "record": {
    "gid": 20513,
    "homeDirectory": "/home/AFOREST/user1",
    "service": "org.samba.winbind",
    "shell": "/bin/bash",
    "uid": 21105,
    "userName": "AFOREST+user1"
  }
}

Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
source3/winbindd/winbindd_varlink.c
source3/winbindd/winbindd_varlink.h
source3/winbindd/winbindd_varlink_getuserrecord.c

index 742d0025868f1e4c1e01085807578752cb17c1d7..20b2265b8b763896c6cea1e0c09df66ee673b811 100644 (file)
@@ -196,6 +196,15 @@ static long io_systemd_getuserrecord(VarlinkService *service,
                                            flags,
                                            parm_service,
                                            parm_name);
+       } else if (parm_name != NULL && parm_uid >= 0) {
+               /* getgrnam + getgrgid */
+               status = wb_vl_user_by_name_and_uid(state,
+                                                   state->ev_ctx,
+                                                   call,
+                                                   flags,
+                                                   parm_service,
+                                                   parm_name,
+                                                   parm_uid);
        }
 
        if (NT_STATUS_IS_ERR(status)) {
index ddf23b437dfc1dcfbb6dfac703e08f62c0bf4cb3..211551739495598e943603cdf186f3f6962cff4f 100644 (file)
@@ -59,6 +59,13 @@ NTSTATUS wb_vl_user_by_name(TALLOC_CTX *mem_ctx,
                            uint64_t flags,
                            const char *service,
                            const char *user_name);
+NTSTATUS wb_vl_user_by_name_and_uid(TALLOC_CTX *mem_ctx,
+                                   struct tevent_context *ev_ctx,
+                                   VarlinkCall *call,
+                                   uint64_t flags,
+                                   const char *service,
+                                   const char *user_name,
+                                   int64_t gid);
 
 bool winbind_setup_varlink(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx);
 
index 874d128672f598a5bd32afd31d3ec5f7eb1dfe4f..5ac4adb64b8405f24eddb3a58e91af0709b02a2b 100644 (file)
@@ -592,3 +592,185 @@ fail:
        TALLOC_FREE(s);
        return status;
 }
+
+/******************************************************************************
+ * User by name and uid
+ * Search by name first, if found, check uid matches.
+ * If not found, search by uid and check name.
+ *****************************************************************************/
+
+struct user_by_name_uid_state {
+       struct tevent_context *ev_ctx;
+       struct winbindd_request *fake_req;
+       struct winbindd_cli_state *fake_cli;
+       VarlinkCall *call;
+       const char *name;
+       uid_t uid;
+};
+
+static int user_by_name_uid_state_destructor(struct user_by_name_uid_state *s)
+{
+       if (s->call != NULL) {
+               s->call = varlink_call_unref(s->call);
+       }
+
+       return 0;
+}
+
+static void user_by_name_uid_getpwnamuid_done(struct tevent_req *req)
+{
+       struct user_by_name_uid_state *s =
+               tevent_req_callback_data(req, struct user_by_name_uid_state);
+       struct winbindd_response *response = NULL;
+       NTSTATUS status;
+
+       /* winbindd_*_recv functions expect a talloc-allocated response */
+       response = talloc_zero(s, struct winbindd_response);
+       if (response == NULL) {
+               DBG_ERR("No memory\n");
+               varlink_call_reply_error(
+                       s->call,
+                       WB_VL_REPLY_ERROR_SERVICE_NOT_AVAILABLE,
+                       NULL);
+               goto out;
+       }
+
+       switch (s->fake_req->cmd) {
+       case WINBINDD_GETPWNAM:
+               status = winbindd_getpwnam_recv(req, response);
+               break;
+       case WINBINDD_GETPWUID:
+               status = winbindd_getpwuid_recv(req, response);
+               break;
+       default:
+               varlink_call_reply_error(
+                       s->call,
+                       WB_VL_REPLY_ERROR_SERVICE_NOT_AVAILABLE,
+                       NULL);
+               TALLOC_FREE(req);
+               goto out;
+       }
+       TALLOC_FREE(req);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+               /*
+                * If name search did not find the user, fall back to uid.
+                * If uid search fails too no record found will be returned.
+                */
+               if (s->fake_req->cmd == WINBINDD_GETPWNAM) {
+                       ZERO_STRUCTP(s->fake_req);
+                       s->fake_req->cmd = WINBINDD_GETPWUID;
+                       s->fake_req->data.uid = s->uid;
+                       req = winbindd_getpwuid_send(s,
+                                                    s->ev_ctx,
+                                                    s->fake_cli,
+                                                    s->fake_req);
+                       if (req == NULL) {
+                               DBG_ERR("No memory\n");
+                               varlink_call_reply_error(
+                                       s->call,
+                                       WB_VL_REPLY_ERROR_SERVICE_NOT_AVAILABLE,
+                                       NULL);
+                               goto out;
+                       }
+                       tevent_req_set_callback(
+                               req,
+                               user_by_name_uid_getpwnamuid_done,
+                               s);
+                       return;
+               }
+               varlink_call_reply_error(s->call,
+                                        WB_VL_REPLY_ERROR_NO_RECORD_FOUND,
+                                        NULL);
+               goto out;
+       } else if (NT_STATUS_IS_ERR(status)) {
+               DBG_ERR("winbindd_getpw[nam|sid] failed: %s\n",
+                       nt_errstr(status));
+               varlink_call_reply_error(
+                       s->call,
+                       WB_VL_REPLY_ERROR_SERVICE_NOT_AVAILABLE,
+                       NULL);
+               goto out;
+       }
+
+       if (response->data.pw.pw_uid != s->uid ||
+           !strequal(response->data.pw.pw_name, s->name)) {
+               varlink_call_reply_error(
+                       s->call,
+                       WB_VL_REPLY_ERROR_CONFLICTING_RECORD_FOUND,
+                       NULL);
+               goto out;
+       }
+
+       user_record_reply(s->call, &response->data.pw, false);
+out:
+       TALLOC_FREE(s);
+}
+
+NTSTATUS wb_vl_user_by_name_and_uid(TALLOC_CTX *mem_ctx,
+                                   struct tevent_context *ev_ctx,
+                                   VarlinkCall *call,
+                                   uint64_t flags,
+                                   const char *service,
+                                   const char *user_name,
+                                   int64_t uid)
+{
+       struct user_by_name_uid_state *s = NULL;
+       struct tevent_req *req = NULL;
+       NTSTATUS status;
+
+       s = talloc_zero(mem_ctx, struct user_by_name_uid_state);
+       if (s == NULL) {
+               DBG_ERR("No memory\n");
+               return NT_STATUS_NO_MEMORY;
+       }
+       talloc_set_destructor(s, user_by_name_uid_state_destructor);
+
+       s->fake_cli = talloc_zero(s, struct winbindd_cli_state);
+       if (s->fake_cli == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->fake_req = talloc_zero(s, struct winbindd_request);
+       if (s->fake_req == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->name = talloc_strdup(s, user_name);
+       if (s->name == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->ev_ctx = ev_ctx;
+       s->uid = uid;
+       s->call = varlink_call_ref(call);
+
+       status = wb_vl_fake_cli_state(call, service, s->fake_cli);
+       if (NT_STATUS_IS_ERR(status)) {
+               DBG_ERR("Failed to create fake winbindd_cli_state: %s\n",
+                       nt_errstr(status));
+               goto fail;
+       }
+
+       s->fake_req->cmd = WINBINDD_GETPWNAM;
+       fstrcpy(s->fake_req->data.username, user_name);
+
+       req = winbindd_getpwnam_send(s, s->ev_ctx, s->fake_cli, s->fake_req);
+       if (req == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+       tevent_req_set_callback(req, user_by_name_uid_getpwnamuid_done, s);
+
+       return NT_STATUS_OK;
+fail:
+       TALLOC_FREE(s);
+       return status;
+}