void tell_become_backup(void) { struct subnet_record *subrec; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { struct server_record *servrec; int num_servers = 0; int num_backups = 0; for (servrec = work->serverlist; servrec; servrec = servrec->next) { num_servers++; if (is_myname(servrec->serv.name)) continue; if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER) { num_backups++; continue; } if (servrec->serv.type & SV_TYPE_MASTER_BROWSER) continue; if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue; DEBUG(3,("num servers: %d num backups: %d\n", num_servers, num_backups)); /* make first server a backup server. thereafter make every tenth server a backup server */ if (num_backups != 0 && (num_servers+9) / num_backups > 10) continue; DEBUG(2,("sending become backup to %s %s for %s\n", servrec->serv.name, inet_ntoa(subrec->bcast_ip), work->work_group)); /* type 11 request from MYNAME(20) to WG(1e) for SERVER */ do_announce_request(servrec->serv.name, work->work_group, ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip); } } } }
void announce_my_servers_removed(void) { int announce_interval = lp_lm_interval(); int lm_announce = lp_lm_announce(); struct subnet_record *subrec; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { struct server_record *servrec; work->announce_interval = 0; for (servrec = work->serverlist; servrec; servrec = servrec->next) { if (!is_myname(servrec->serv.name)) continue; servrec->serv.type = 0; if(AM_LOCAL_MASTER_BROWSER(work)) send_local_master_announcement(subrec, work, servrec); send_host_announcement(subrec, work, servrec); if ((announce_interval <= 0) || (lm_announce <= 0)) { /* user absolutely does not want LM announcements to be sent. */ continue; } if ((lm_announce >= 2) && (!found_lm_clients)) { /* has been set to 2 (Auto) but no LM clients detected (yet). */ continue; } /* * lm announce was set or we have seen lm announcements, so do * a lm announcement of host removed. */ send_lm_host_announcement(subrec, work, servrec, 0); } } } }
static bool check_domain_match(const char *user, const char *domain) { /* * If we aren't serving to trusted domains, we must make sure that * the validation request comes from an account in the same domain * as the Samba server */ if (!lp_allow_trusted_domains() && !(strequal("", domain) || strequal(lp_workgroup(), domain) || is_myname(domain))) { DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); return False; } else { return True; } }
void announce_my_lm_server_names(time_t t) { struct subnet_record *subrec; static time_t last_lm_announce_time=0; int announce_interval = lp_lm_interval(); int lm_announce = lp_lm_announce(); if ((announce_interval <= 0) || (lm_announce <= 0)) { /* user absolutely does not want LM announcements to be sent. */ return; } if ((lm_announce >= 2) && (!found_lm_clients)) { /* has been set to 2 (Auto) but no LM clients detected (yet). */ return; } /* Otherwise: must have been set to 1 (Yes), or LM clients *have* been detected. */ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup); if(work) { struct server_record *servrec; if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval )) continue; last_lm_announce_time = t; for (servrec = work->serverlist; servrec; servrec = servrec->next) { if (is_myname(servrec->serv.name)) /* skipping equivalent of announce_server() */ send_lm_host_announcement(subrec, work, servrec, announce_interval); } } /* if work */ } /* for subrec */ }
static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context, void *my_private_data, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { bool is_local_name, is_my_domain; if (!user_info || !auth_context) { return NT_STATUS_LOGON_FAILURE; } DEBUG(10, ("Check auth for: [%s]\n", user_info->mapped.account_name)); is_local_name = is_myname(user_info->mapped.domain_name); is_my_domain = strequal(user_info->mapped.domain_name, lp_workgroup()); /* check whether or not we service this domain/workgroup name */ switch ( lp_server_role() ) { case ROLE_STANDALONE: case ROLE_DOMAIN_MEMBER: if ( !is_local_name ) { DEBUG(6,("check_samstrict_security: %s is not one of my local names (%s)\n", user_info->mapped.domain_name, (lp_server_role() == ROLE_DOMAIN_MEMBER ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") )); return NT_STATUS_NOT_IMPLEMENTED; } case ROLE_DOMAIN_PDC: case ROLE_DOMAIN_BDC: if ( !is_local_name && !is_my_domain ) { DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", user_info->mapped.domain_name)); return NT_STATUS_NOT_IMPLEMENTED; } default: /* name is ok */ break; } return check_sam_security(&auth_context->challenge, mem_ctx, user_info, server_info); }
void announce_my_server_names(time_t t) { struct subnet_record *subrec; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup); if(work) { struct server_record *servrec; if (work->needannounce) { /* Drop back to a max 3 minute announce. This is to prevent a single lost packet from breaking things for too long. */ work->announce_interval = MIN(work->announce_interval, CHECK_TIME_MIN_HOST_ANNCE*60); work->lastannounce_time = t - (work->announce_interval+1); work->needannounce = False; } /* Announce every minute at first then progress to every 12 mins */ if ((t - work->lastannounce_time) < work->announce_interval) continue; if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60)) work->announce_interval += 60; work->lastannounce_time = t; for (servrec = work->serverlist; servrec; servrec = servrec->next) { if (is_myname(servrec->serv.name)) announce_server(subrec, work, servrec); } } /* if work */ } /* for subrec */ }
enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) { NTSTATUS result; unsigned char trust_passwd[16]; time_t last_change_time; uint32 sec_channel_type; NET_USER_INFO_3 info3; struct cli_state *cli = NULL; TALLOC_CTX *mem_ctx = NULL; char *name_user = NULL; const char *name_domain = NULL; const char *workstation; struct winbindd_domain *contact_domain; DOM_CRED ret_creds; int attempts = 0; BOOL retry; DATA_BLOB lm_resp, nt_resp; if (!state->privileged) { char *error_string = NULL; DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access denied. !\n")); DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions on %s are set correctly.\n", get_winbind_priv_pipe_dir())); /* send a better message than ACCESS_DENIED */ asprintf(&error_string, "winbind client not authorized to use winbindd_pam_auth_crap. Ensure permissions on %s are set correctly.", get_winbind_priv_pipe_dir()); push_utf8_fstring(state->response.data.auth.error_string, error_string); SAFE_FREE(error_string); result = NT_STATUS_ACCESS_DENIED; goto done; } /* Ensure null termination */ state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0; state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0; if (!(mem_ctx = talloc_init("winbind pam auth crap for (utf8) %s", state->request.data.auth_crap.user))) { DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n")); result = NT_STATUS_NO_MEMORY; goto done; } if (pull_utf8_talloc(mem_ctx, &name_user, state->request.data.auth_crap.user) == (size_t)-1) { DEBUG(0, ("winbindd_pam_auth_crap: pull_utf8_talloc failed!\n")); result = NT_STATUS_UNSUCCESSFUL; goto done; } if (*state->request.data.auth_crap.domain) { char *dom = NULL; if (pull_utf8_talloc(mem_ctx, &dom, state->request.data.auth_crap.domain) == (size_t)-1) { DEBUG(0, ("winbindd_pam_auth_crap: pull_utf8_talloc failed!\n")); result = NT_STATUS_UNSUCCESSFUL; goto done; } name_domain = dom; } else if (lp_winbind_use_default_domain()) { name_domain = lp_workgroup(); } else { DEBUG(5,("no domain specified with username (%s) - failing auth\n", name_user)); result = NT_STATUS_NO_SUCH_USER; goto done; } DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid, name_domain, name_user)); if (*state->request.data.auth_crap.workstation) { char *wrk = NULL; if (pull_utf8_talloc(mem_ctx, &wrk, state->request.data.auth_crap.workstation) == (size_t)-1) { DEBUG(0, ("winbindd_pam_auth_crap: pull_utf8_talloc failed!\n")); result = NT_STATUS_UNSUCCESSFUL; goto done; } workstation = wrk; } else { workstation = global_myname(); } if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp) || state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) { DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n", state->request.data.auth_crap.lm_resp_len, state->request.data.auth_crap.nt_resp_len)); result = NT_STATUS_INVALID_PARAMETER; goto done; } lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len); nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len); /* what domain should we contact? */ if ( IS_DC ) { if (!(contact_domain = find_domain_from_name(name_domain))) { DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", state->request.data.auth_crap.user, name_domain, name_user, name_domain)); result = NT_STATUS_NO_SUCH_USER; goto done; } } else { if (is_myname(name_domain)) { DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain)); result = NT_STATUS_NO_SUCH_USER; goto done; } if (!(contact_domain = find_our_domain())) { DEBUG(1, ("Authenticatoin for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n", state->request.data.auth_crap.user, name_domain, name_user)); result = NT_STATUS_NO_SUCH_USER; goto done; } } if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) { result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; goto done; } do { ZERO_STRUCT(info3); ZERO_STRUCT(ret_creds); retry = False; /* Don't shut this down - it belongs to the connection cache code */ result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli); if (!NT_STATUS_IS_OK(result)) { DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", nt_errstr(result))); goto done; } result = cli_netlogon_sam_network_logon(cli, mem_ctx, &ret_creds, name_user, name_domain, workstation, state->request.data.auth_crap.chal, lm_resp, nt_resp, &info3); attempts += 1; /* We have to try a second time as cm_get_netlogon_cli might not yet have noticed that the DC has killed our connection. */ if ( cli->fd == -1 ) { retry = True; continue; } /* if we get access denied, a possible cause was that we had and open connection to the DC, but someone changed our machine account password out from underneath us using 'net rpc changetrustpw' */ if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) { DEBUG(3,("winbindd_pam_auth_crap: sam_logon returned ACCESS_DENIED. Maybe the trust account " "password was changed and we didn't know it. Killing connections to domain %s\n", contact_domain->name)); winbindd_cm_flush(); retry = True; cli = NULL; } } while ( (attempts < 2) && retry ); if (cli != NULL) { /* We might have come out of the loop above with cli == NULL, so don't dereference that. */ clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds); } if (NT_STATUS_IS_OK(result)) { netsamlogon_cache_store( cli->mem_ctx, &info3 ); wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3); if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth_crap.required_membership_sid))) { DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n", state->request.data.auth_crap.user, state->request.data.auth_crap.required_membership_sid)); goto done; } if (state->request.flags & WBFLAG_PAM_INFO3_NDR) { result = append_info3_as_ndr(mem_ctx, state, &info3); } else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) { /* ntlm_auth should return the unix username, per 'winbind use default domain' settings and the like */ fstring username_out; const char *nt_username, *nt_domain; if (!(nt_username = unistr2_tdup(mem_ctx, &(info3.uni_user_name)))) { /* If the server didn't give us one, just use the one we sent them */ nt_username = name_user; } if (!(nt_domain = unistr2_tdup(mem_ctx, &(info3.uni_logon_dom)))) { /* If the server didn't give us one, just use the one we sent them */ nt_domain = name_domain; } fill_domain_username(username_out, nt_domain, nt_username); DEBUG(5, ("Setting unix username to [%s]\n", username_out)); /* this interface is in UTF8 */ if (push_utf8_allocate((char **)&state->response.extra_data, username_out) == -1) { result = NT_STATUS_NO_MEMORY; goto done; } state->response.length += strlen(state->response.extra_data)+1; } if (state->request.flags & WBFLAG_PAM_USER_SESSION_KEY) { memcpy(state->response.data.auth.user_session_key, info3.user_sess_key, sizeof(state->response.data.auth.user_session_key) /* 16 */); } if (state->request.flags & WBFLAG_PAM_LMKEY) { memcpy(state->response.data.auth.first_8_lm_hash, info3.padding, sizeof(state->response.data.auth.first_8_lm_hash) /* 8 */); } } done: /* give us a more useful (more correct?) error code */ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) || (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) { result = NT_STATUS_NO_LOGON_SERVERS; } if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) { result = nt_status_squash(result); } state->response.data.auth.nt_status = NT_STATUS_V(result); push_utf8_fstring(state->response.data.auth.nt_status_string, nt_errstr(result)); /* we might have given a more useful error above */ if (!*state->response.data.auth.error_string) push_utf8_fstring(state->response.data.auth.error_string, get_friendly_nt_error_msg(result)); state->response.data.auth.pam_error = nt_status_to_pam(result); DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n", name_domain, name_user, state->response.data.auth.nt_status_string, state->response.data.auth.pam_error)); if (mem_ctx) talloc_destroy(mem_ctx); return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; }
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) { NTSTATUS result; fstring name_domain, name_user; unsigned char trust_passwd[16]; time_t last_change_time; uint32 sec_channel_type; NET_USER_INFO_3 info3; struct cli_state *cli = NULL; uchar chal[8]; TALLOC_CTX *mem_ctx = NULL; DATA_BLOB lm_resp; DATA_BLOB nt_resp; DOM_CRED ret_creds; int attempts = 0; unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; struct winbindd_domain *contact_domain; BOOL retry; /* Ensure null termination */ state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0'; /* Ensure null termination */ state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0'; DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid, state->request.data.auth.user)); if (!(mem_ctx = talloc_init("winbind pam auth for %s", state->request.data.auth.user))) { DEBUG(0, ("winbindd_pam_auth: could not talloc_init()!\n")); result = NT_STATUS_NO_MEMORY; goto done; } /* Parse domain and username */ parse_domain_user(state->request.data.auth.user, name_domain, name_user); /* do password magic */ generate_random_buffer(chal, 8); SMBencrypt(state->request.data.auth.pass, chal, local_lm_response); SMBNTencrypt(state->request.data.auth.pass, chal, local_nt_response); lm_resp = data_blob_talloc(mem_ctx, local_lm_response, sizeof(local_lm_response)); nt_resp = data_blob_talloc(mem_ctx, local_nt_response, sizeof(local_nt_response)); /* what domain should we contact? */ if ( IS_DC ) { if (!(contact_domain = find_domain_from_name(name_domain))) { DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", state->request.data.auth.user, name_domain, name_user, name_domain)); result = NT_STATUS_NO_SUCH_USER; goto done; } } else { if (is_myname(name_domain)) { DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain)); result = NT_STATUS_NO_SUCH_USER; goto done; } if (!(contact_domain = find_our_domain())) { DEBUG(1, ("Authentication for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n", state->request.data.auth.user, name_domain, name_user)); result = NT_STATUS_NO_SUCH_USER; goto done; } } if ( !get_trust_pw(contact_domain->name, trust_passwd, &last_change_time, &sec_channel_type) ) { result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; goto done; } /* check authentication loop */ do { ZERO_STRUCT(info3); ZERO_STRUCT(ret_creds); retry = False; /* Don't shut this down - it belongs to the connection cache code */ result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli); if (!NT_STATUS_IS_OK(result)) { DEBUG(3, ("could not open handle to NETLOGON pipe\n")); goto done; } result = cli_netlogon_sam_network_logon(cli, mem_ctx, &ret_creds, name_user, name_domain, global_myname(), chal, lm_resp, nt_resp, &info3); attempts += 1; /* We have to try a second time as cm_get_netlogon_cli might not yet have noticed that the DC has killed our connection. */ if ( cli->fd == -1 ) { retry = True; continue; } /* if we get access denied, a possible cuase was that we had and open connection to the DC, but someone changed our machine account password out from underneath us using 'net rpc changetrustpw' */ if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) ) { DEBUG(3,("winbindd_pam_auth: sam_logon returned ACCESS_DENIED. Maybe the trust account " "password was changed and we didn't know it. Killing connections to domain %s\n", name_domain)); winbindd_cm_flush(); retry = True; cli = NULL; } } while ( (attempts < 2) && retry ); if (cli != NULL) { /* We might have come out of the loop above with cli == NULL, so don't dereference that. */ clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds); } if (NT_STATUS_IS_OK(result)) { netsamlogon_cache_store( cli->mem_ctx, &info3 ); wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3); /* Check if the user is in the right group */ if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth.required_membership_sid))) { DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n", state->request.data.auth.user, state->request.data.auth.required_membership_sid)); } } done: /* give us a more useful (more correct?) error code */ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) || (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) { result = NT_STATUS_NO_LOGON_SERVERS; } state->response.data.auth.nt_status = NT_STATUS_V(result); fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result)); /* we might have given a more useful error above */ if (!*state->response.data.auth.error_string) fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result)); state->response.data.auth.pam_error = nt_status_to_pam(result); DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n", state->request.data.auth.user, state->response.data.auth.nt_status_string, state->response.data.auth.pam_error)); if ( NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_AFS_TOKEN) ) { char *afsname = strdup(lp_afs_username_map()); char *cell; if (afsname == NULL) goto no_token; afsname = realloc_string_sub(afsname, "%D", name_domain); afsname = realloc_string_sub(afsname, "%u", name_user); afsname = realloc_string_sub(afsname, "%U", name_user); if (afsname == NULL) goto no_token; strlower_m(afsname); cell = strchr(afsname, '@'); if (cell == NULL) goto no_token; *cell = '\0'; cell += 1; /* Append an AFS token string */ state->response.extra_data = afs_createtoken_str(afsname, cell); if (state->response.extra_data != NULL) state->response.length += strlen(state->response.extra_data)+1; no_token: SAFE_FREE(afsname); } if (mem_ctx) talloc_destroy(mem_ctx); return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; }
void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf) { struct dgram_packet *dgram = &p->packet.dgram; int ttl = IVAL(buf,1)/1000; unstring announce_name; uint32 servertype = IVAL(buf,23); fstring comment; struct work_record *work; struct server_record *servrec; unstring work_name; unstring source_name; START_PROFILE(host_announce); pull_ascii_fstring(comment, buf+31); pull_ascii_nstring(announce_name, sizeof(announce_name), buf+5); pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name); DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \ %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name),announce_name)); DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n", ttl, servertype,comment)); /* Filter servertype to remove impossible bits. */ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM); /* A host announcement must be sent to the name WORKGROUP<1d>. */ if(dgram->dest_name.name_type != 0x1d) { DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \ (was %02x) should be 0x1d. Allowing packet anyway.\n", inet_ntoa(p->ip), dgram->dest_name.name_type)); /* Change it so it was. */ dgram->dest_name.name_type = 0x1d; } /* For a host announce the workgroup name is the destination name. */ pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name); /* * Syntax servers version 5.1 send HostAnnounce packets to * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00> * instead of WORKGROUP<1d> name. So to fix this we check if * the workgroup name is our own name, and if so change it * to be our primary workgroup name. */ if(strequal(work_name, global_myname())) unstrcpy(work_name,lp_workgroup()); /* * We are being very agressive here in adding a workgroup * name on the basis of a host announcing itself as being * in that workgroup. Maybe we should wait for the workgroup * announce instead ? JRA. */ work = find_workgroup_on_subnet(subrec, work_name); if(servertype != 0) { if (work ==NULL ) { /* We have no record of this workgroup. Add it. */ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL) goto done; } if((servrec = find_server_in_workgroup( work, announce_name))==NULL) { /* If this server is not already in the workgroup, add it. */ create_server_on_workgroup(work, announce_name, servertype|SV_TYPE_LOCAL_LIST_ONLY, ttl, comment); } else { /* Update the record. */ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY; update_server_ttl( servrec, ttl); fstrcpy(servrec->serv.comment,comment); } } else { /* * This server is announcing it is going down. Remove it from the * workgroup. */ if(!is_myname(announce_name) && (work != NULL) && ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) { remove_server_from_workgroup( work, servrec); } } subrec->work_changed = True; done: END_PROFILE(host_announce); }
void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf) { struct dgram_packet *dgram = &p->packet.dgram; int ttl = IVAL(buf,1)/1000; unstring server_name; uint32 servertype = IVAL(buf,23); fstring comment; unstring work_name; struct work_record *work; struct server_record *servrec; unstring source_name; START_PROFILE(local_master_announce); pull_ascii_nstring(server_name,sizeof(server_name),buf+5); pull_ascii_fstring(comment, buf+31); pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name); pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name); DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \ %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name),server_name)); DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n", ttl, servertype, comment)); /* A local master announcement must be sent to the name WORKGROUP<1e>. */ if(dgram->dest_name.name_type != 0x1e) { DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \ (was %02x) should be 0x1e. Ignoring packet.\n", inet_ntoa(p->ip), dgram->dest_name.name_type)); goto done; } /* Filter servertype to remove impossible bits. */ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM); /* For a local master announce the workgroup name is the destination name. */ if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL) { /* Don't bother adding if it's a local master release announce. */ if(servertype == 0) goto done; /* We have no record of this workgroup. Add it. */ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL) goto done; } /* If we think we're the local master browser for this workgroup, we should never have got this packet. We don't see our own packets. */ if(AM_LOCAL_MASTER_BROWSER(work)) { DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \ a local master browser for workgroup %s and we think we are master. Forcing election.\n", server_name, inet_ntoa(p->ip), work_name)); /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when they have become a local master browser once, they will never stop sending local master announcements. To fix this we send them a reset browser packet, with level 0x2 on the __SAMBA__ name that only they should be listening to. */ send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip); /* We should demote ourself and force an election. */ unbecome_local_master_browser( subrec, work, True); /* The actual election requests are handled in nmbd_election.c */ goto done; } /* Find the server record on this workgroup. If it doesn't exist, add it. */ if(servertype != 0) { if((servrec = find_server_in_workgroup( work, server_name))==NULL) { /* If this server is not already in the workgroup, add it. */ create_server_on_workgroup(work, server_name, servertype|SV_TYPE_LOCAL_LIST_ONLY, ttl, comment); } else { /* Update the record. */ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY; update_server_ttl(servrec, ttl); fstrcpy(servrec->serv.comment,comment); } set_workgroup_local_master_browser_name( work, server_name ); } else { /* * This server is announcing it is going down. Remove it from the * workgroup. */ if(!is_myname(server_name) && (work != NULL) && ((servrec = find_server_in_workgroup( work, server_name))!=NULL)) { remove_server_from_workgroup( work, servrec); } } subrec->work_changed = True; done: END_PROFILE(local_master_announce); }
static void hprf(const char *fmt, int mesg, FILE *f, int threaded, const char *attrlist) { struct message *mp = &message[mesg-1]; char *headline = NULL, *subjline, *name, *cp, *pbuf = NULL; struct headline hl; size_t headsize = 0; const char *fp; int B, c, i, n, s; int headlen = 0; struct str in, out; int subjlen = scrnwidth, fromlen, isto = 0, isaddr = 0; FILE *ibuf; if ((mp->m_flag & MNOFROM) == 0) { if ((ibuf = setinput(&mb, mp, NEED_HEADER)) == NULL) return; if ((headlen = readline(ibuf, &headline, &headsize)) < 0) return; } if ((subjline = hfield("subject", mp)) == NULL) subjline = hfield("subj", mp); if (subjline == NULL) { out.s = NULL; out.l = 0; } else { in.s = subjline; in.l = strlen(subjline); mime_fromhdr(&in, &out, TD_ICONV | TD_ISPR); subjline = out.s; } if ((mp->m_flag & MNOFROM) == 0) { pbuf = ac_alloc(headlen + 1); parse(headline, headlen, &hl, pbuf); } else { hl.l_from = /*fakefrom(mp);*/NULL; hl.l_tty = NULL; hl.l_date = fakedate(mp->m_time); } if (value("datefield") && (cp = hfield("date", mp)) != NULL) hl.l_date = fakedate(rfctime(cp)); if (Iflag) { if ((name = hfield("newsgroups", mp)) == NULL) if ((name = hfield("article-id", mp)) == NULL) name = "<>"; name = prstr(name); } else if (value("show-rcpt") == NULL) { name = name1(mp, 0); isaddr = 1; if (value("showto") && name && is_myname(skin(name))) { if ((cp = hfield("to", mp)) != NULL) { name = cp; isto = 1; } } } else { isaddr = 1; if ((name = hfield("to", mp)) != NULL) isto = 1; } if (name == NULL) { name = ""; isaddr = 0; } if (isaddr) { if (value("showname")) name = realname(name); else { name = prstr(skin(name)); } } for (fp = fmt; *fp; fp++) { if (*fp == '%') { if (*++fp == '-') { fp++; } else if (*fp == '+') fp++; while (digitchar(*fp&0377)) fp++; if (*fp == '\0') break; } else { #if defined (HAVE_MBTOWC) && defined (HAVE_WCWIDTH) if (mb_cur_max > 1) { wchar_t wc; if ((s = mbtowc(&wc, fp, mb_cur_max)) < 0) n = s = 1; else { if ((n = wcwidth(wc)) < 0) n = 1; } } else #endif /* HAVE_MBTOWC && HAVE_WCWIDTH */ { n = s = 1; } subjlen -= n; while (--s > 0) fp++; } } for (fp = fmt; *fp; fp++) { if (*fp == '%') { B = 0; n = 0; s = 1; if (*++fp == '-') { s = -1; fp++; } else if (*fp == '+') fp++; if (digitchar(*fp&0377)) { do n = 10*n + *fp - '0'; while (fp++, digitchar(*fp&0377)); } if (*fp == '\0') break; n *= s; switch (*fp) { case '%': putc('%', f); subjlen--; break; case '>': case '<': c = dot == mp ? *fp&0377 : ' '; putc(c, f); subjlen--; break; case 'a': c = dispc(mp, attrlist); putc(c, f); subjlen--; break; case 'm': if (n == 0) { n = 3; if (threaded) for (i=msgCount; i>999; i/=10) n++; } subjlen -= fprintf(f, "%*d", n, mesg); break; case 'f': if (n <= 0) n = 18; fromlen = n; if (isto) fromlen -= 3; fprintf(f, "%s%s", isto ? "To " : "", colalign(name, fromlen, 1)); subjlen -= n; break; case 'd': if (n <= 0) n = 16; subjlen -= fprintf(f, "%*.*s", n, n, hl.l_date); break; case 'l': if (n == 0) n = 4; if (mp->m_xlines) subjlen -= fprintf(f, "%*ld", n, mp->m_xlines); else { subjlen -= n; while (n--) putc(' ', f); } break; case 'o': if (n == 0) n = -5; subjlen -= fprintf(f, "%*lu", n, (long)mp->m_xsize); break; case 'i': if (threaded) subjlen -= putindent(f, mp, scrnwidth - 60); break; case 'S': B = 1; /*FALLTHRU*/ case 's': n = n>0 ? n : subjlen - 2; if (B) n -= 2; if (subjline != NULL && n >= 0) { /* pretty pathetic */ fprintf(f, B ? "\"%s\"" : "%s", colalign(subjline, n, 0)); } break; case 'U': if (n == 0) n = 9; subjlen -= fprintf(f, "%*lu", n, mp->m_uid); break; case 'e': if (n == 0) n = 2; subjlen -= fprintf(f, "%*u", n, threaded == 1 ? mp->m_level : 0); break; case 't': if (n == 0) { n = 3; if (threaded) for (i=msgCount; i>999; i/=10) n++; } fprintf(f, "%*ld", n, threaded ? mp->m_threadpos : mesg); subjlen -= n; break; case 'c': if (n == 0) n = 6; subjlen -= fprintf(f, "%*g", n, mp->m_score); break; } } else putc(*fp&0377, f); } putc('\n', f); if (out.s) free(out.s); if (headline) free(headline); if (pbuf) ac_free(pbuf); }