1/* 2 Unix SMB/CIFS implementation. 3 async implementation of WINBINDD_GETGRNAM 4 Copyright (C) Volker Lendecke 2009 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "winbindd.h" 22 23struct winbindd_getgrnam_state { 24 struct tevent_context *ev; 25 fstring name_domain, name_group; 26 struct dom_sid sid; 27 const char *domname; 28 const char *name; 29 gid_t gid; 30 struct talloc_dict *members; 31}; 32 33static void winbindd_getgrnam_lookupsid_done(struct tevent_req *subreq); 34static void winbindd_getgrnam_done(struct tevent_req *subreq); 35 36struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx, 37 struct tevent_context *ev, 38 struct winbindd_cli_state *cli, 39 struct winbindd_request *request) 40{ 41 struct tevent_req *req, *subreq; 42 struct winbindd_getgrnam_state *state; 43 char *tmp; 44 NTSTATUS nt_status; 45 46 req = tevent_req_create(mem_ctx, &state, 47 struct winbindd_getgrnam_state); 48 if (req == NULL) { 49 return NULL; 50 } 51 state->ev = ev; 52 53 /* Ensure null termination */ 54 request->data.groupname[sizeof(request->data.groupname)-1]='\0'; 55 56 DEBUG(3, ("getgrnam %s\n", request->data.groupname)); 57 58 nt_status = normalize_name_unmap(state, request->data.groupname, &tmp); 59 /* If we didn't map anything in the above call, just reset the 60 tmp pointer to the original string */ 61 if (!NT_STATUS_IS_OK(nt_status) && 62 !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) 63 { 64 tmp = request->data.groupname; 65 } 66 67 /* Parse domain and groupname */ 68 69 parse_domain_user(tmp, state->name_domain, state->name_group); 70 71 /* if no domain or our local domain and no local tdb group, default to 72 * our local domain for aliases */ 73 74 if ( !*(state->name_domain) || strequal(state->name_domain, 75 get_global_sam_name()) ) { 76 fstrcpy(state->name_domain, get_global_sam_name()); 77 } 78 79 subreq = wb_lookupname_send(state, ev, state->name_domain, state->name_group, 80 0); 81 if (tevent_req_nomem(subreq, req)) { 82 return tevent_req_post(req, ev); 83 } 84 tevent_req_set_callback(subreq, winbindd_getgrnam_lookupsid_done, 85 req); 86 return req; 87} 88 89static void winbindd_getgrnam_lookupsid_done(struct tevent_req *subreq) 90{ 91 struct tevent_req *req = tevent_req_callback_data( 92 subreq, struct tevent_req); 93 struct winbindd_getgrnam_state *state = tevent_req_data( 94 req, struct winbindd_getgrnam_state); 95 enum lsa_SidType type; 96 NTSTATUS status; 97 98 status = wb_lookupname_recv(subreq, &state->sid, &type); 99 TALLOC_FREE(subreq); 100 if (!NT_STATUS_IS_OK(status)) { 101 tevent_req_nterror(req, status); 102 return; 103 } 104 105 if ( (type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) ) { 106 DEBUG(5,("getgrnam_recv: not a group!\n")); 107 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP); 108 return; 109 } 110 111 subreq = wb_getgrsid_send(state, state->ev, &state->sid, 112 lp_winbind_expand_groups()); 113 if (tevent_req_nomem(subreq, req)) { 114 return; 115 } 116 tevent_req_set_callback(subreq, winbindd_getgrnam_done, req); 117} 118 119static void winbindd_getgrnam_done(struct tevent_req *subreq) 120{ 121 struct tevent_req *req = tevent_req_callback_data( 122 subreq, struct tevent_req); 123 struct winbindd_getgrnam_state *state = tevent_req_data( 124 req, struct winbindd_getgrnam_state); 125 NTSTATUS status; 126 127 status = wb_getgrsid_recv(subreq, state, &state->domname, &state->name, 128 &state->gid, &state->members); 129 TALLOC_FREE(subreq); 130 if (!NT_STATUS_IS_OK(status)) { 131 tevent_req_nterror(req, status); 132 return; 133 } 134 tevent_req_done(req); 135} 136 137NTSTATUS winbindd_getgrnam_recv(struct tevent_req *req, 138 struct winbindd_response *response) 139{ 140 struct winbindd_getgrnam_state *state = tevent_req_data( 141 req, struct winbindd_getgrnam_state); 142 NTSTATUS status; 143 int num_members; 144 char *buf; 145 146 if (tevent_req_is_nterror(req, &status)) { 147 DEBUG(5, ("Could not convert sid %s: %s\n", 148 sid_string_dbg(&state->sid), nt_errstr(status))); 149 return status; 150 } 151 152 if (!fill_grent(talloc_tos(), &response->data.gr, state->domname, 153 state->name, state->gid)) { 154 DEBUG(5, ("fill_grent failed\n")); 155 return NT_STATUS_NO_MEMORY; 156 } 157 158 status = winbindd_print_groupmembers(state->members, response, 159 &num_members, &buf); 160 if (!NT_STATUS_IS_OK(status)) { 161 return status; 162 } 163 164 response->data.gr.num_gr_mem = (uint32)num_members; 165 166 /* Group membership lives at start of extra data */ 167 168 response->data.gr.gr_mem_ofs = 0; 169 response->extra_data.data = buf; 170 response->length += talloc_get_size(response->extra_data.data); 171 172 return NT_STATUS_OK; 173} 174