From 9a1ceab6d60549f3c983dd1cf1f9a9ea2ba5dc79 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 20 Sep 2005 20:54:25 +0000 Subject: r10363: Nobody loudly screamed "noo", so commit the samba3 winbind interface to samba4. Ok, maybe the silence is due to timezones, but what can you do... ;-) Volker (This used to be commit 9a5d8f55ab2841572b94fbc3a86a47f65a7d74a6) --- source4/winbind/wb_server.c | 190 +++++++++++++++++++++++- source4/winbind/winbindd_nss.h | 323 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 510 insertions(+), 3 deletions(-) create mode 100644 source4/winbind/winbindd_nss.h diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c index e35651c6e5..0bea86f38e 100644 --- a/source4/winbind/wb_server.c +++ b/source4/winbind/wb_server.c @@ -28,12 +28,14 @@ #include "lib/events/events.h" #include "smbd/service_task.h" #include "smbd/service_stream.h" +#include "winbind/winbindd_nss.h" #define WINBINDD_DIR "/tmp/.winbindd/" #define WINBINDD_ECHO_SOCKET WINBINDD_DIR"echo" #define WINBINDD_ADDR_PREFIX "127.0.255." #define WINBINDD_ECHO_ADDR WINBINDD_ADDR_PREFIX"1" #define WINBINDD_ECHO_PORT 55555 +#define WINBINDD_SAMBA3_SOCKET WINBINDD_DIR"pipe" /* state of an open winbind connection @@ -126,13 +128,184 @@ static void winbind_send(struct stream_connection *conn, uint16_t flags) EVENT_FD_NOT_WRITEABLE(conn->event.fde); } -static const struct stream_server_ops winbind_stream_ops = { +static const struct stream_server_ops winbind_echo_ops = { .name = "winbind_echo", .accept_connection = winbind_accept, .recv_handler = winbind_recv, .send_handler = winbind_send, }; +struct winbind3_connection { + struct winbindd_request *request; + struct winbindd_response *response; + DATA_BLOB partial; + size_t nsent; +}; + +static void winbind_samba3_accept(struct stream_connection *conn) +{ + struct winbind3_connection *wbconn; + + wbconn = talloc(conn, struct winbind3_connection); + if (wbconn == NULL) { + DEBUG(0, ("talloc failed\n")); + stream_terminate_connection(conn, "talloc failed"); + return; + } + + wbconn->request = NULL; + wbconn->response = NULL; + ZERO_STRUCT(wbconn->partial); + conn->private = wbconn; +} + +static void winbind_samba3_recv(struct stream_connection *conn, uint16_t flags) +{ + struct winbind3_connection *wbconn = + talloc_get_type(conn->private, struct winbind3_connection); + size_t npending, received; + NTSTATUS res; + + if (!NT_STATUS_IS_OK(socket_pending(conn->socket, &npending))) { + stream_terminate_connection(conn, "socket_pending() failed"); + return; + } + + if (npending == 0) { + stream_terminate_connection(conn, "EOF from client"); + return; + } + + if (wbconn->partial.length + npending > + sizeof(struct winbindd_request)) { + npending = sizeof(struct winbindd_request) - + wbconn->partial.length; + } + + wbconn->partial.data = + talloc_realloc_size(wbconn, wbconn->partial.data, + wbconn->partial.length + npending); + if (wbconn->partial.data == NULL) { + stream_terminate_connection(conn, "talloc_realloc failed"); + return; + } + + res = socket_recv(conn->socket, + &wbconn->partial.data[wbconn->partial.length], + npending, &received, 0); + + if (!NT_STATUS_IS_OK(res)) { + DEBUG(5, ("sock_recv failed: %s\n", nt_errstr(res))); + stream_terminate_connection(conn, "talloc_realloc failed"); + return; + } + + wbconn->partial.length += received; + + if (wbconn->partial.length < sizeof(struct winbindd_request)) { + return; + } + + wbconn->request = (struct winbindd_request *)wbconn->partial.data; + + SMB_ASSERT(wbconn->response == NULL); + + wbconn->response = talloc_zero(wbconn, struct winbindd_response); + if (wbconn->response == NULL) { + stream_terminate_connection(conn, "talloc_zero failed"); + return; + } + + wbconn->response->length = sizeof(struct winbindd_response); + wbconn->response->result = WINBINDD_ERROR; + + if (wbconn->request->length != sizeof(struct winbindd_request)) { + DEBUG(10, ("Got invalid request length %d\n", + wbconn->request->length)); + goto done; + } + + DEBUG(10, ("Got winbind request %d\n", wbconn->request->cmd)); + + switch(wbconn->request->cmd) { + case WINBINDD_INTERFACE_VERSION: + wbconn->response->result = WINBINDD_OK; + wbconn->response->data.interface_version = + WINBIND_INTERFACE_VERSION; + break; + case WINBINDD_PRIV_PIPE_DIR: + wbconn->response->result = WINBINDD_OK; + wbconn->response->extra_data = + smbd_tmp_path(wbconn->response, "winbind_priv/pipe"); + if (wbconn->response->extra_data == NULL) { + stream_terminate_connection(conn, + "smbd_tmp_path failed"); + return; + } + wbconn->response->length += + strlen(wbconn->response->extra_data) + 1; + break; + case WINBINDD_PING: + wbconn->response->result = WINBINDD_OK; + break; + default: + break; + } + + done: + talloc_free(wbconn->partial.data); + wbconn->partial.data = NULL; + wbconn->nsent = 0; + + wbconn->partial.data = (char *)wbconn->response; + wbconn->partial.length = sizeof(struct winbindd_response); + + EVENT_FD_NOT_READABLE(conn->event.fde); + EVENT_FD_WRITEABLE(conn->event.fde); +} + +static void winbind_samba3_send(struct stream_connection *conn, uint16_t flags) +{ + struct winbind3_connection *wbconn = + talloc_get_type(conn->private, struct winbind3_connection); + size_t nsent; + NTSTATUS res; + + res = socket_send(conn->socket, &wbconn->partial, &nsent, 0); + if (!NT_STATUS_IS_OK(res)) { + stream_terminate_connection(conn, "socket_send() failed"); + return; + } + + wbconn->partial.data += nsent; + wbconn->partial.length -= nsent; + + if (wbconn->partial.length != 0) { + return; + } + + if (wbconn->response->extra_data != NULL) { + wbconn->partial.data = wbconn->response->extra_data; + wbconn->partial.length = wbconn->response->length - + sizeof(struct winbindd_response); + wbconn->response->extra_data = NULL; + return; + } + + talloc_free(wbconn->response); + wbconn->response = NULL; + wbconn->partial.data = NULL; + EVENT_FD_NOT_WRITEABLE(conn->event.fde); + EVENT_FD_READABLE(conn->event.fde); +} + +static const struct stream_server_ops winbind_samba3_ops = { + .name = "winbind_samba3", + .accept_connection = winbind_samba3_accept, + .recv_handler = winbind_samba3_recv, + .send_handler = winbind_samba3_send, +}; + /* startup the winbind task */ @@ -156,7 +329,7 @@ static void winbind_task_init(struct task_server *task) mkdir(WINBINDD_DIR, 0755); } - status = stream_setup_socket(task->event_ctx, model_ops, &winbind_stream_ops, + status = stream_setup_socket(task->event_ctx, model_ops, &winbind_echo_ops, "unix", WINBINDD_ECHO_SOCKET, &port, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", @@ -165,9 +338,20 @@ static void winbind_task_init(struct task_server *task) return; } + status = stream_setup_socket(task->event_ctx, model_ops, + &winbind_samba3_ops, "unix", + WINBINDD_SAMBA3_SOCKET, &port, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", + WINBINDD_ECHO_SOCKET, nt_errstr(status))); + task_server_terminate(task, "winbind Failed to find to " + "SAMBA3 unix socket"); + return; + } + port = WINBINDD_ECHO_PORT; - status = stream_setup_socket(task->event_ctx, model_ops, &winbind_stream_ops, + status = stream_setup_socket(task->event_ctx, model_ops, &winbind_echo_ops, "ipv4", WINBINDD_ECHO_ADDR, &port, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", diff --git a/source4/winbind/winbindd_nss.h b/source4/winbind/winbindd_nss.h new file mode 100644 index 0000000000..04f6d9a823 --- /dev/null +++ b/source4/winbind/winbindd_nss.h @@ -0,0 +1,323 @@ +/* + Unix SMB/CIFS implementation. + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + You are free to use this interface definition in any way you see + fit, including without restriction, using this header in your own + products. You do not need to give any attribution. +*/ + + +#ifndef _WINBINDD_NSS_H +#define _WINBINDD_NSS_H + +typedef char fstring[256]; + + +/* Update this when you change the interface. */ + +#define WINBIND_INTERFACE_VERSION 11 + +/* Socket commands */ + +enum winbindd_cmd { + + WINBINDD_INTERFACE_VERSION, /* Always a well known value */ + + /* Get users and groups */ + + WINBINDD_GETPWNAM, + WINBINDD_GETPWUID, + WINBINDD_GETGRNAM, + WINBINDD_GETGRGID, + WINBINDD_GETGROUPS, + + /* Enumerate users and groups */ + + WINBINDD_SETPWENT, + WINBINDD_ENDPWENT, + WINBINDD_GETPWENT, + WINBINDD_SETGRENT, + WINBINDD_ENDGRENT, + WINBINDD_GETGRENT, + + /* PAM authenticate and password change */ + + WINBINDD_PAM_AUTH, + WINBINDD_PAM_AUTH_CRAP, + WINBINDD_PAM_CHAUTHTOK, + + /* List various things */ + + WINBINDD_LIST_USERS, /* List w/o rid->id mapping */ + WINBINDD_LIST_GROUPS, /* Ditto */ + WINBINDD_LIST_TRUSTDOM, + + /* SID conversion */ + + WINBINDD_LOOKUPSID, + WINBINDD_LOOKUPNAME, + + /* Lookup functions */ + + WINBINDD_SID_TO_UID, + WINBINDD_SID_TO_GID, + WINBINDD_UID_TO_SID, + WINBINDD_GID_TO_SID, + WINBINDD_ALLOCATE_RID, + WINBINDD_ALLOCATE_RID_AND_GID, + + /* Miscellaneous other stuff */ + + WINBINDD_CHECK_MACHACC, /* Check machine account pw works */ + WINBINDD_PING, /* Just tell me winbind is running */ + WINBINDD_INFO, /* Various bit of info. Currently just tidbits */ + WINBINDD_DOMAIN_NAME, /* The domain this winbind server is a member of (lp_workgroup()) */ + + WINBINDD_DOMAIN_INFO, /* Most of what we know from + struct winbindd_domain */ + WINBINDD_GETDCNAME, /* Issue a GetDCName Request */ + + WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */ + + /* WINS commands */ + + WINBINDD_WINS_BYIP, + WINBINDD_WINS_BYNAME, + + /* this is like GETGRENT but gives an empty group list */ + WINBINDD_GETGRLST, + + WINBINDD_NETBIOS_NAME, /* The netbios name of the server */ + + /* find the location of our privileged pipe */ + WINBINDD_PRIV_PIPE_DIR, + + /* return a list of group sids for a user sid */ + WINBINDD_GETUSERSIDS, + + /* Return the domain groups a user is in */ + WINBINDD_GETUSERDOMGROUPS, + + /* Initialize connection in a child */ + WINBINDD_INIT_CONNECTION, + + /* Blocking calls that are not allowed on the main winbind pipe, only + * between parent and children */ + WINBINDD_DUAL_SID2UID, + WINBINDD_DUAL_SID2GID, + WINBINDD_DUAL_IDMAPSET, + + /* Wrapper around possibly blocking unix nss calls */ + WINBINDD_DUAL_UID2NAME, + WINBINDD_DUAL_NAME2UID, + WINBINDD_DUAL_GID2NAME, + WINBINDD_DUAL_NAME2GID, + + WINBINDD_DUAL_USERINFO, + WINBINDD_DUAL_GETSIDALIASES, + + WINBINDD_NUM_CMDS +}; + +typedef struct winbindd_pw { + fstring pw_name; + fstring pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + fstring pw_gecos; + fstring pw_dir; + fstring pw_shell; +} WINBINDD_PW; + + +typedef struct winbindd_gr { + fstring gr_name; + fstring gr_passwd; + gid_t gr_gid; + int num_gr_mem; + int gr_mem_ofs; /* offset to group membership */ + char **gr_mem; +} WINBINDD_GR; + + +#define WBFLAG_PAM_INFO3_NDR 0x0001 +#define WBFLAG_PAM_INFO3_TEXT 0x0002 +#define WBFLAG_PAM_USER_SESSION_KEY 0x0004 +#define WBFLAG_PAM_LMKEY 0x0008 +#define WBFLAG_PAM_CONTACT_TRUSTDOM 0x0010 +#define WBFLAG_QUERY_ONLY 0x0020 +#define WBFLAG_ALLOCATE_RID 0x0040 +#define WBFLAG_PAM_UNIX_NAME 0x0080 +#define WBFLAG_PAM_AFS_TOKEN 0x0100 +#define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200 + +/* This is a flag that can only be sent from parent to child */ +#define WBFLAG_IS_PRIVILEGED 0x0400 + +/* Winbind request structure */ + +struct winbindd_request { + uint32_t length; + enum winbindd_cmd cmd; /* Winbindd command to execute */ + pid_t pid; /* pid of calling process */ + uint32_t flags; /* flags relavant to a given request */ + fstring domain_name; /* name of domain for which the request + * applies */ + int msgid; + + union { + fstring winsreq; /* WINS request */ + fstring username; /* getpwnam */ + fstring groupname; /* getgrnam */ + uid_t uid; /* getpwuid, uid_to_sid */ + gid_t gid; /* getgrgid, gid_to_sid */ + struct { + /* We deliberatedly don't split into domain/user to + avoid having the client know what the separator + character is. */ + fstring user; + fstring pass; + fstring require_membership_of_sid; + } auth; /* pam_winbind auth module */ + struct { + unsigned char chal[8]; + fstring user; + fstring domain; + fstring lm_resp; + uint16_t lm_resp_len; + fstring nt_resp; + uint16_t nt_resp_len; + fstring workstation; + fstring require_membership_of_sid; + } auth_crap; + struct { + fstring user; + fstring oldpass; + fstring newpass; + } chauthtok; /* pam_winbind passwd module */ + fstring sid; /* lookupsid, sid_to_[ug]id */ + struct { + fstring dom_name; /* lookupname */ + fstring name; + } name; + uint32_t num_entries; /* getpwent, getgrent */ + struct { + fstring username; + fstring groupname; + } acct_mgt; + struct { + BOOL is_primary; + fstring dcname; + } init_conn; + struct { + fstring sid; + fstring name; + BOOL alloc; + } dual_sid2id; + struct { + int type; + uid_t uid; + gid_t gid; + fstring sid; + } dual_idmapset; + struct { + fstring cache_key; + } dual_sidaliases; + } data; + char null_term; +}; + +/* Response values */ + +enum winbindd_result { + WINBINDD_ERROR, + WINBINDD_PENDING, + WINBINDD_OK +}; + +/* Winbind response structure */ + +struct winbindd_response { + + /* Header information */ + + uint32_t length; /* Length of response */ + enum winbindd_result result; /* Result code */ + + /* Fixed length return data */ + + union { + int interface_version; /* Try to ensure this is always in the + * same spot... */ + + fstring winsresp; /* WINS response */ + + /* getpwnam, getpwuid */ + + struct winbindd_pw pw; + + /* getgrnam, getgrgid */ + + struct winbindd_gr gr; + + uint32_t num_entries; /* getpwent, getgrent */ + struct winbindd_sid { + fstring sid; /* lookupname, [ug]id_to_sid */ + int type; + } sid; + struct winbindd_name { + fstring dom_name; /* lookupsid */ + fstring name; + int type; + } name; + uid_t uid; /* sid_to_uid */ + gid_t gid; /* sid_to_gid */ + struct winbindd_info { + char winbind_separator; + fstring samba_version; + } info; + fstring domain_name; + fstring netbios_name; + fstring dc_name; + + struct auth_reply { + uint32_t nt_status; + fstring nt_status_string; + fstring error_string; + int pam_error; + char user_session_key[16]; + char first_8_lm_hash[8]; + } auth; + uint32_t rid; /* create user or group or allocate rid */ + struct { + uint32_t rid; + gid_t gid; + } rid_and_gid; + struct { + fstring name; + fstring alt_name; + fstring sid; + BOOL native_mode; + BOOL active_directory; + BOOL primary; + uint32_t sequence_number; + } domain_info; + struct { + fstring acct_name; + fstring full_name; + fstring homedir; + fstring shell; + uint32_t group_rid; + } user_info; + } data; + + /* Variable length return data */ + + void *extra_data; /* getgrnam, getgrgid, getgrent */ +}; + +#endif -- cgit