1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind daemon - miscellaneous other functions 5 6 Copyright (C) Tim Potter 2000 7 Copyright (C) Andrew Bartlett 2002 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22*/ 23 24#include "includes.h" 25#include "winbindd.h" 26 27#undef DBGC_CLASS 28#define DBGC_CLASS DBGC_WINBIND 29 30/* Check the machine account password is valid */ 31 32enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state) 33{ 34 NTSTATUS result = NT_STATUS_UNSUCCESSFUL; 35 uchar trust_passwd[16]; 36 int num_retries = 0; 37 struct cli_state *cli; 38 uint32 sec_channel_type; 39 struct winbindd_domain *contact_domain; 40 41 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid)); 42 43 /* Get trust account password */ 44 45 again: 46 if (!secrets_fetch_trust_account_password( 47 lp_workgroup(), trust_passwd, NULL, &sec_channel_type)) { 48 result = NT_STATUS_INTERNAL_ERROR; 49 goto done; 50 } 51 52 53 contact_domain = find_our_domain(); 54 if (!contact_domain) { 55 result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 56 DEBUG(1, ("Cannot find our own domain!\n")); 57 goto done; 58 } 59 60 /* This call does a cli_nt_setup_creds() which implicitly checks 61 the trust account password. */ 62 /* Don't shut this down - it belongs to the connection cache code */ 63 64 result = cm_get_netlogon_cli(contact_domain, 65 trust_passwd, sec_channel_type, True, &cli); 66 67 if (!NT_STATUS_IS_OK(result)) { 68 DEBUG(3, ("could not open handle to NETLOGON pipe\n")); 69 goto done; 70 } 71 72 /* There is a race condition between fetching the trust account 73 password and the periodic machine password change. So it's 74 possible that the trust account password has been changed on us. 75 We are returned NT_STATUS_ACCESS_DENIED if this happens. */ 76 77#define MAX_RETRIES 8 78 79 if ((num_retries < MAX_RETRIES) && 80 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) { 81 num_retries++; 82 goto again; 83 } 84 85 /* Pass back result code - zero for success, other values for 86 specific failures. */ 87 88 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ? 89 "good" : "bad")); 90 91 done: 92 state->response.data.auth.nt_status = NT_STATUS_V(result); 93 fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result)); 94 fstrcpy(state->response.data.auth.error_string, nt_errstr(result)); 95 state->response.data.auth.pam_error = nt_status_to_pam(result); 96 97 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n", 98 state->response.data.auth.nt_status_string)); 99 100 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; 101} 102 103enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state 104 *state) 105{ 106 struct winbindd_domain *domain; 107 int total_entries = 0, extra_data_len = 0; 108 char *ted, *extra_data = NULL; 109 110 DEBUG(3, ("[%5lu]: list trusted domains\n", (unsigned long)state->pid)); 111 112 /* We need to refresh the trusted domain list as the domains may 113 have changed since we last looked. There may be a sequence 114 number or something we should use but I haven't found it yet. */ 115 116 if (!init_domain_list()) { 117 DEBUG(1, ("winbindd_list_trusted_domains: could not " 118 "refresh trusted domain list\n")); 119 return WINBINDD_ERROR; 120 } 121 122 for(domain = domain_list(); domain; domain = domain->next) { 123 124 /* Skip own domain */ 125 126 if (domain->primary) continue; 127 128 /* Add domain to list */ 129 130 total_entries++; 131 ted = SMB_REALLOC(extra_data, sizeof(fstring) * 132 total_entries); 133 134 if (!ted) { 135 DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n")); 136 SAFE_FREE(extra_data); 137 return WINBINDD_ERROR; 138 } else 139 extra_data = ted; 140 141 memcpy(&extra_data[extra_data_len], domain->name, 142 strlen(domain->name)); 143 144 extra_data_len += strlen(domain->name); 145 extra_data[extra_data_len++] = ','; 146 } 147 148 if (extra_data) { 149 if (extra_data_len > 1) 150 extra_data[extra_data_len - 1] = '\0'; 151 state->response.extra_data = extra_data; 152 state->response.length += extra_data_len; 153 } 154 155 return WINBINDD_OK; 156} 157 158 159enum winbindd_result winbindd_show_sequence(struct winbindd_cli_state *state) 160{ 161 struct winbindd_domain *domain; 162 char *extra_data = NULL; 163 const char *which_domain; 164 165 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid)); 166 167 /* Ensure null termination */ 168 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0'; 169 which_domain = state->request.domain_name; 170 171 extra_data = SMB_STRDUP(""); 172 173 /* this makes for a very simple data format, and is easily parsable as well 174 if that is ever needed */ 175 for (domain = domain_list(); domain; domain = domain->next) { 176 char *s; 177 178 /* if we have a domain name restricting the request and this 179 one in the list doesn't match, then just bypass the remainder 180 of the loop */ 181 182 if ( *which_domain && !strequal(which_domain, domain->name) ) 183 continue; 184 185 domain->methods->sequence_number(domain, &domain->sequence_number); 186 187 if (DOM_SEQUENCE_NONE == (unsigned)domain->sequence_number) { 188 asprintf(&s,"%s%s : DISCONNECTED\n", extra_data, 189 domain->name); 190 } else { 191 asprintf(&s,"%s%s : %u\n", extra_data, 192 domain->name, (unsigned)domain->sequence_number); 193 } 194 free(extra_data); 195 extra_data = s; 196 } 197 198 state->response.extra_data = extra_data; 199 /* must add one to length to copy the 0 for string termination */ 200 state->response.length += strlen(extra_data) + 1; 201 202 return WINBINDD_OK; 203} 204 205enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state) 206{ 207 struct winbindd_domain *domain; 208 209 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid, 210 state->request.domain_name)); 211 212 domain = find_domain_from_name(state->request.domain_name); 213 214 if (domain == NULL) { 215 DEBUG(3, ("Did not find domain [%s]\n", 216 state->request.domain_name)); 217 return WINBINDD_ERROR; 218 } 219 220 fstrcpy(state->response.data.domain_info.name, domain->name); 221 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name); 222 fstrcpy(state->response.data.domain_info.sid, 223 sid_string_static(&domain->sid)); 224 225 state->response.data.domain_info.native_mode = domain->native_mode; 226 state->response.data.domain_info.active_directory = domain->active_directory; 227 state->response.data.domain_info.primary = domain->primary; 228 229 state->response.data.domain_info.sequence_number = 230 domain->sequence_number; 231 232 return WINBINDD_OK; 233} 234 235enum winbindd_result winbindd_ping(struct winbindd_cli_state 236 *state) 237{ 238 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid)); 239 240 return WINBINDD_OK; 241} 242 243/* List various tidbits of information */ 244 245enum winbindd_result winbindd_info(struct winbindd_cli_state *state) 246{ 247 248 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid)); 249 250 state->response.data.info.winbind_separator = *lp_winbind_separator(); 251 fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING); 252 253 return WINBINDD_OK; 254} 255 256/* Tell the client the current interface version */ 257 258enum winbindd_result winbindd_interface_version(struct winbindd_cli_state *state) 259{ 260 261 DEBUG(3, ("[%5lu]: request interface version\n", (unsigned long)state->pid)); 262 263 state->response.data.interface_version = WINBIND_INTERFACE_VERSION; 264 265 return WINBINDD_OK; 266} 267 268/* What domain are we a member of? */ 269 270enum winbindd_result winbindd_domain_name(struct winbindd_cli_state *state) 271{ 272 273 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid)); 274 275 fstrcpy(state->response.data.domain_name, lp_workgroup()); 276 277 return WINBINDD_OK; 278} 279 280/* What's my name again? */ 281 282enum winbindd_result winbindd_netbios_name(struct winbindd_cli_state *state) 283{ 284 285 DEBUG(3, ("[%5lu]: request netbios name\n", (unsigned long)state->pid)); 286 287 fstrcpy(state->response.data.netbios_name, global_myname()); 288 289 return WINBINDD_OK; 290} 291 292/* Where can I find the privilaged pipe? */ 293 294enum winbindd_result winbindd_priv_pipe_dir(struct winbindd_cli_state *state) 295{ 296 297 DEBUG(3, ("[%5lu]: request location of privileged pipe\n", (unsigned long)state->pid)); 298 299 state->response.extra_data = SMB_STRDUP(get_winbind_priv_pipe_dir()); 300 if (!state->response.extra_data) 301 return WINBINDD_ERROR; 302 303 /* must add one to length to copy the 0 for string termination */ 304 state->response.length += strlen((char *)state->response.extra_data) + 1; 305 306 return WINBINDD_OK; 307} 308