void check_dhcp_hosts(int fatal) { /* If the same IP appears in more than one host config, then DISCOVER for one of the hosts will get the address, but REQUEST will be NAKed, since the address is reserved by the other one -> protocol loop. Also check that FQDNs match the domain we are using. */ struct dhcp_config *configs, *cp; for (configs = daemon->dhcp_conf; configs; configs = configs->next) { char *domain; if ((configs->flags & DHOPT_BANK) || fatal) { for (cp = configs->next; cp; cp = cp->next) if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr) { if (fatal) die(_("duplicate IP address %s in dhcp-config directive."), inet_ntoa(cp->addr), EC_BADCONF); else my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."), inet_ntoa(cp->addr), daemon->dhcp_hosts_file); configs->flags &= ~CONFIG_ADDR; } /* split off domain part */ if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname))) configs->domain = domain; } } }
void dhcp_init(void) { int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); struct sockaddr_in saddr; int oneopt = 1; struct dhcp_config *configs, *cp; if (fd == -1) die (_("cannot create DHCP socket : %s"), NULL, EC_BADNET); if (!fix_fd(fd) || #if defined(HAVE_LINUX_NETWORK) setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 || #elif defined(IP_RECVIF) setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 || #endif setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1) die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET); /* When bind-interfaces is set, there might be more than one dnmsasq instance binding port 67. That's OK if they serve different networks. Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. OpenBSD <= 4.0 screws up IP_RECVIF when SO_REUSEPORT is set, but OpenBSD <= 3.9 doesn't have IP_RECVIF anyway, so we just have to elide this for OpenBSD 4.0, if you want more than one instance on oBSD4.0, tough. */ #ifndef OpenBSD4_0 if (daemon->options & OPT_NOWILD) { #ifdef SO_REUSEPORT int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt)); #else int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)); #endif if (rc == -1) die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET); } #endif memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(DHCP_SERVER_PORT); saddr.sin_addr.s_addr = INADDR_ANY; #ifdef HAVE_SOCKADDR_SA_LEN saddr.sin_len = sizeof(struct sockaddr_in); #endif if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))) die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET); daemon->dhcpfd = fd; #ifndef HAVE_LINUX_NETWORK /* When we're not using capabilities, we need to do this here before we drop root. Also, set buffer size small, to avoid wasting kernel buffers */ if (daemon->options & OPT_NO_PING) daemon->dhcp_icmp_fd = -1; else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 || setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 ) die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET); /* Make BPF raw send socket */ init_bpf(); #endif /* If the same IP appears in more than one host config, then DISCOVER for one of the hosts will get the address, but REQUEST will be NAKed, since the address is reserved by the other one -> protocol loop. Also check that FQDNs match the domain we are using. */ for (configs = daemon->dhcp_conf; configs; configs = configs->next) { char *domain; for (cp = configs->next; cp; cp = cp->next) if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr) die(_("duplicate IP address %s in dhcp-config directive."), inet_ntoa(cp->addr), EC_BADCONF); if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname))) die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF); } daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet); daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len); }
WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx, struct NetGetJoinableOUs *r) { #ifdef WITH_ADS NTSTATUS status; ADS_STATUS ads_status; ADS_STRUCT *ads = NULL; struct netr_DsRGetDCNameInfo *info = NULL; const char *dc = NULL; uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME; status = dsgetdcname(ctx, NULL, r->in.domain, NULL, NULL, flags, &info); if (!NT_STATUS_IS_OK(status)) { libnetapi_set_error_string(ctx, "%s", get_friendly_nt_error_msg(status)); return ntstatus_to_werror(status); } dc = strip_hostname(info->dc_unc); ads = ads_init(info->domain_name, info->domain_name, dc); if (!ads) { return WERR_GENERAL_FAILURE; } SAFE_FREE(ads->auth.user_name); if (r->in.account) { ads->auth.user_name = SMB_STRDUP(r->in.account); } else if (ctx->username) { ads->auth.user_name = SMB_STRDUP(ctx->username); } SAFE_FREE(ads->auth.password); if (r->in.password) { ads->auth.password = SMB_STRDUP(r->in.password); } else if (ctx->password) { ads->auth.password = SMB_STRDUP(ctx->password); } ads_status = ads_connect_user_creds(ads); if (!ADS_ERR_OK(ads_status)) { ads_destroy(&ads); return WERR_DEFAULT_JOIN_REQUIRED; } ads_status = ads_get_joinable_ous(ads, ctx, (char ***)r->out.ous, (size_t *)r->out.ou_count); if (!ADS_ERR_OK(ads_status)) { ads_destroy(&ads); return WERR_DEFAULT_JOIN_REQUIRED; } ads_destroy(&ads); return WERR_OK; #else return WERR_NOT_SUPPORTED; #endif }
WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx, struct NetJoinDomain *r) { struct libnet_JoinCtx *j = NULL; WERROR werr; if (!r->in.domain) { return WERR_INVALID_PARAM; } werr = libnet_init_JoinCtx(mem_ctx, &j); W_ERROR_NOT_OK_RETURN(werr); j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain); W_ERROR_HAVE_NO_MEMORY(j->in.domain_name); if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) { NTSTATUS status; struct netr_DsRGetDCNameInfo *info = NULL; const char *dc = NULL; uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED | DS_WRITABLE_REQUIRED | DS_RETURN_DNS_NAME; status = dsgetdcname(mem_ctx, NULL, r->in.domain, NULL, NULL, flags, &info); if (!NT_STATUS_IS_OK(status)) { libnetapi_set_error_string(mem_ctx, "%s", get_friendly_nt_error_msg(status)); return ntstatus_to_werror(status); } dc = strip_hostname(info->dc_unc); j->in.dc_name = talloc_strdup(mem_ctx, dc); W_ERROR_HAVE_NO_MEMORY(j->in.dc_name); } if (r->in.account_ou) { j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou); W_ERROR_HAVE_NO_MEMORY(j->in.account_ou); } if (r->in.account) { j->in.admin_account = talloc_strdup(mem_ctx, r->in.account); W_ERROR_HAVE_NO_MEMORY(j->in.admin_account); } if (r->in.password) { j->in.admin_password = talloc_strdup(mem_ctx, r->in.password); W_ERROR_HAVE_NO_MEMORY(j->in.admin_password); } j->in.join_flags = r->in.join_flags; j->in.modify_config = true; j->in.debug = true; werr = libnet_Join(mem_ctx, j); if (!W_ERROR_IS_OK(werr) && j->out.error_string) { libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string); } TALLOC_FREE(j); return werr; }
WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx, struct NetUnjoinDomain *r) { struct libnet_UnjoinCtx *u = NULL; struct dom_sid domain_sid; const char *domain = NULL; WERROR werr; if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { return WERR_SETUP_NOT_JOINED; } werr = libnet_init_UnjoinCtx(mem_ctx, &u); W_ERROR_NOT_OK_RETURN(werr); if (lp_realm()) { domain = lp_realm(); } else { domain = lp_workgroup(); } if (r->in.server_name) { u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name); W_ERROR_HAVE_NO_MEMORY(u->in.dc_name); } else { NTSTATUS status; struct netr_DsRGetDCNameInfo *info = NULL; const char *dc = NULL; uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED | DS_WRITABLE_REQUIRED | DS_RETURN_DNS_NAME; status = dsgetdcname(mem_ctx, NULL, domain, NULL, NULL, flags, &info); if (!NT_STATUS_IS_OK(status)) { libnetapi_set_error_string(mem_ctx, "failed to find DC for domain %s: %s", domain, get_friendly_nt_error_msg(status)); return ntstatus_to_werror(status); } dc = strip_hostname(info->dc_unc); u->in.dc_name = talloc_strdup(mem_ctx, dc); W_ERROR_HAVE_NO_MEMORY(u->in.dc_name); u->in.domain_name = domain; } if (r->in.account) { u->in.admin_account = talloc_strdup(mem_ctx, r->in.account); W_ERROR_HAVE_NO_MEMORY(u->in.admin_account); } if (r->in.password) { u->in.admin_password = talloc_strdup(mem_ctx, r->in.password); W_ERROR_HAVE_NO_MEMORY(u->in.admin_password); } u->in.domain_name = domain; u->in.unjoin_flags = r->in.unjoin_flags; u->in.delete_machine_account = false; u->in.modify_config = true; u->in.debug = true; u->in.domain_sid = &domain_sid; werr = libnet_Unjoin(mem_ctx, u); if (!W_ERROR_IS_OK(werr) && u->out.error_string) { libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string); } TALLOC_FREE(u); return werr; }