/** * Set an IP to 0.0.0.0. */ void zero_ip_v4(struct in_addr *ip) { ZERO_STRUCTP(ip); }
static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) { TDB_DATA result; int num_valid = 0; int i; struct locking_data *data; ssize_t offset; ssize_t sp_len; uint32 delete_token_size; result.dptr = NULL; result.dsize = 0; for (i=0; i<lck->num_share_modes; i++) { if (!is_unused_share_mode_entry(&lck->share_modes[i])) { num_valid += 1; } } if (num_valid == 0) { return result; } sp_len = strlen(lck->servicepath); delete_token_size = (lck->delete_token ? (sizeof(uid_t) + sizeof(gid_t) + (lck->delete_token->ngroups*sizeof(gid_t))) : 0); result.dsize = sizeof(*data) + lck->num_share_modes * sizeof(struct share_mode_entry) + delete_token_size + sp_len + 1 + strlen(lck->filename) + 1; result.dptr = talloc_size(lck, result.dsize); if (result.dptr == NULL) { smb_panic("talloc failed\n"); } data = (struct locking_data *)result.dptr; ZERO_STRUCTP(data); data->u.s.num_share_mode_entries = lck->num_share_modes; data->u.s.delete_on_close = lck->delete_on_close; data->u.s.initial_delete_on_close = lck->initial_delete_on_close; data->u.s.delete_token_size = delete_token_size; DEBUG(10, ("unparse_share_modes: del: %d, initial del %d, tok = %u, num: %d\n", data->u.s.delete_on_close, data->u.s.initial_delete_on_close, (unsigned int)data->u.s.delete_token_size, data->u.s.num_share_mode_entries)); memcpy(result.dptr + sizeof(*data), lck->share_modes, sizeof(struct share_mode_entry)*lck->num_share_modes); offset = sizeof(*data) + sizeof(struct share_mode_entry)*lck->num_share_modes; /* Store any delete on close token. */ if (lck->delete_token) { char *p = result.dptr + offset; memcpy(p, &lck->delete_token->uid, sizeof(uid_t)); p += sizeof(uid_t); memcpy(p, &lck->delete_token->gid, sizeof(gid_t)); p += sizeof(gid_t); for (i = 0; i < lck->delete_token->ngroups; i++) { memcpy(p, &lck->delete_token->groups[i], sizeof(gid_t)); p += sizeof(gid_t); } offset = p - result.dptr; } safe_strcpy(result.dptr + offset, lck->servicepath, result.dsize - offset - 1); offset += sp_len + 1; safe_strcpy(result.dptr + offset, lck->filename, result.dsize - offset - 1); if (DEBUGLEVEL >= 10) { print_share_mode_table(data); } return result; }
/* * Connect to a server for getting/setting attributes, possibly on an existing * connection. This works similarly to SMBC_server(). */ SMBCSRV * SMBC_attr_server(TALLOC_CTX *ctx, SMBCCTX *context, const char *server, uint16_t port, const char *share, char **pp_workgroup, char **pp_username, char **pp_password) { int flags; struct cli_state *ipc_cli = NULL; struct rpc_pipe_client *pipe_hnd = NULL; NTSTATUS nt_status; SMBCSRV *srv=NULL; SMBCSRV *ipc_srv=NULL; /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ srv = SMBC_server(ctx, context, true, server, port, share, pp_workgroup, pp_username, pp_password); if (!srv) { return NULL; } server = smbXcli_conn_remote_name(srv->cli->conn); share = srv->cli->share; /* * See if we've already created this special connection. Reference * our "special" share name '*IPC$', which is an impossible real share * name due to the leading asterisk. */ ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$", pp_workgroup, pp_username, pp_password); if (!ipc_srv) { int signing_state = SMB_SIGNING_DEFAULT; /* We didn't find a cached connection. Get the password */ if (!*pp_password || (*pp_password)[0] == '\0') { /* ... then retrieve it now. */ SMBC_call_auth_fn(ctx, context, server, share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } } flags = 0; if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (smbc_getOptionUseCCache(context)) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) { signing_state = SMB_SIGNING_REQUIRED; } nt_status = cli_full_connection(&ipc_cli, lp_netbios_name(), server, NULL, 0, "IPC$", "?????", *pp_username, *pp_workgroup, *pp_password, flags, signing_state); if (! NT_STATUS_IS_OK(nt_status)) { DEBUG(1,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); errno = ENOTSUP; return NULL; } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli, *pp_username, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == * 1 means don't fail if encryption can't be * negotiated, == 2 means fail if encryption * can't be negotiated. */ DEBUG(4,(" SMB encrypt failed on IPC$\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(ipc_cli); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok on IPC$\n")); } ipc_srv = SMB_MALLOC_P(SMBCSRV); if (!ipc_srv) { errno = ENOMEM; cli_shutdown(ipc_cli); return NULL; } ZERO_STRUCTP(ipc_srv); DLIST_ADD(ipc_srv->cli, ipc_cli); nt_status = cli_rpc_pipe_open_noauth( ipc_srv->cli, &ndr_table_lsarpc, &pipe_hnd); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("cli_nt_session_open fail!\n")); errno = ENOTSUP; cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } /* * Some systems don't support * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000 * so we might as well do it too. */ nt_status = rpccli_lsa_open_policy( pipe_hnd, talloc_tos(), True, GENERIC_EXECUTE_ACCESS, &ipc_srv->pol); if (!NT_STATUS_IS_OK(nt_status)) { errno = SMBC_errno(context, ipc_srv->cli); cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv, server, "*IPC$", *pp_workgroup, *pp_username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; } cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } DLIST_ADD(context->internal->servers, ipc_srv); } return ipc_srv; }
/* parse an ACE in the same format as print_ace() */ static BOOL parse_ace(SEC_ACE *ace, char *str) { char *p; const char *cp; fstring tok; unsigned atype, aflags, amask; DOM_SID sid; SEC_ACCESS mask; struct perm_value *v; ZERO_STRUCTP(ace); p = strchr(str,':'); if (!p) return False; *p = '\0'; p++; /* Try to parse numeric form */ if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && StringToSid(&sid, str)) { goto done; } /* Try to parse text form */ if (!StringToSid(&sid, str)) { return False; } cp = p; if (!next_token(&cp, tok, "/", sizeof(fstring))) { return False; } if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { atype = SEC_ACE_TYPE_ACCESS_ALLOWED; } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) { atype = SEC_ACE_TYPE_ACCESS_DENIED; } else { return False; } /* Only numeric form accepted for flags at present */ if (!(next_token(&cp, tok, "/", sizeof(fstring)) && sscanf(tok, "%i", &aflags))) { return False; } if (!next_token(&cp, tok, "/", sizeof(fstring))) { return False; } if (strncmp(tok, "0x", 2) == 0) { if (sscanf(tok, "%i", &amask) != 1) { return False; } goto done; } for (v = standard_values; v->perm; v++) { if (strcmp(tok, v->perm) == 0) { amask = v->mask; goto done; } } p = tok; while(*p) { BOOL found = False; for (v = special_values; v->perm; v++) { if (v->perm[0] == *p) { amask |= v->mask; found = True; } } if (!found) return False; p++; } if (*p) { return False; } done: mask.mask = amask; init_sec_ace(ace, &sid, atype, mask, aflags); return True; }
bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout, const char **endp) { const char *p; char *q; /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ uint64_t conv; ZERO_STRUCTP(sidout); if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') { goto format_error; } /* Get the revision number. */ p = sidstr + 2; if (!isdigit(*p)) { goto format_error; } conv = strtoul(p, &q, 10); if (!q || (*q != '-') || conv > UINT8_MAX) { goto format_error; } sidout->sid_rev_num = (uint8_t) conv; q++; if (!isdigit(*q)) { goto format_error; } /* get identauth */ conv = strtoull(q, &q, 0); if (!q || conv & AUTHORITY_MASK) { goto format_error; } /* When identauth >= UINT32_MAX, it's in hex with a leading 0x */ /* NOTE - the conv value is in big-endian format. */ sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40; sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32; sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24; sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16; sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8; sidout->id_auth[5] = (conv & 0x0000000000ffULL); sidout->num_auths = 0; if (*q != '-') { /* Just id_auth, no subauths */ goto done; } q++; while (true) { char *end; if (!isdigit(*q)) { goto format_error; } conv = strtoull(q, &end, 10); if (end == q || conv > UINT32_MAX) { goto format_error; } if (!sid_append_rid(sidout, conv)) { DEBUG(3, ("Too many sid auths in %s\n", sidstr)); return false; } q = end; if (*q != '-') { break; } q += 1; } done: if (endp != NULL) { *endp = q; } return true; format_error: DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr)); return false; }
static struct subnet_record *make_subnet(const char *name, enum subnet_type type, struct in_addr myip, struct in_addr bcast_ip, struct in_addr mask_ip) { struct subnet_record *subrec = NULL; int nmb_sock = -1; int dgram_sock = -1; int nmb_bcast = -1; int dgram_bcast = -1; bool bind_bcast = lp_nmbd_bind_explicit_broadcast(); /* Check if we are creating a non broadcast subnet - if so don't create sockets. */ if (type == NORMAL_SUBNET) { struct sockaddr_storage ss; struct sockaddr_storage ss_bcast; in_addr_to_sockaddr_storage(&ss, myip); in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip); /* * Attempt to open the sockets on port 137/138 for this interface * and bind them. * Fail the subnet creation if this fails. */ nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port, 0, &ss, true); if (nmb_sock == -1) { DEBUG(0, ("nmbd_subnetdb:make_subnet()\n")); DEBUGADD(0,(" Failed to open nmb socket on interface %s ", inet_ntoa(myip))); DEBUGADD(0,("for port %d. ", global_nmb_port)); DEBUGADD(0,("Error was %s\n", strerror(errno))); goto failed; } set_socket_options(nmb_sock,"SO_BROADCAST"); set_blocking(nmb_sock, false); if (bind_bcast) { nmb_bcast = open_socket_in(SOCK_DGRAM, global_nmb_port, 0, &ss_bcast, true); if (nmb_bcast == -1) { DEBUG(0, ("nmbd_subnetdb:make_subnet()\n")); DEBUGADD(0,(" Failed to open nmb bcast socket on interface %s ", inet_ntoa(bcast_ip))); DEBUGADD(0,("for port %d. ", global_nmb_port)); DEBUGADD(0,("Error was %s\n", strerror(errno))); goto failed; } set_socket_options(nmb_bcast, "SO_BROADCAST"); set_blocking(nmb_bcast, false); } dgram_sock = open_socket_in(SOCK_DGRAM, DGRAM_PORT, 3, &ss, true); if (dgram_sock == -1) { DEBUG(0, ("nmbd_subnetdb:make_subnet()\n")); DEBUGADD(0,(" Failed to open dgram socket on interface %s ", inet_ntoa(myip))); DEBUGADD(0,("for port %d. ", DGRAM_PORT)); DEBUGADD(0,("Error was %s\n", strerror(errno))); goto failed; } set_socket_options(dgram_sock, "SO_BROADCAST"); set_blocking(dgram_sock, false); if (bind_bcast) { dgram_bcast = open_socket_in(SOCK_DGRAM, DGRAM_PORT, 3, &ss_bcast, true); if (dgram_bcast == -1) { DEBUG(0, ("nmbd_subnetdb:make_subnet()\n")); DEBUGADD(0,(" Failed to open dgram bcast socket on interface %s ", inet_ntoa(bcast_ip))); DEBUGADD(0,("for port %d. ", DGRAM_PORT)); DEBUGADD(0,("Error was %s\n", strerror(errno))); goto failed; } set_socket_options(dgram_bcast, "SO_BROADCAST"); set_blocking(dgram_bcast, false); } } subrec = SMB_MALLOC_P(struct subnet_record); if (!subrec) { DEBUG(0,("make_subnet: malloc fail !\n")); goto failed; } ZERO_STRUCTP(subrec); if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) { DEBUG(0,("make_subnet: malloc fail for subnet name !\n")); goto failed; } DEBUG(2, ("making subnet name:%s ", name )); DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip))); DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip))); subrec->namelist_changed = False; subrec->work_changed = False; subrec->bcast_ip = bcast_ip; subrec->mask_ip = mask_ip; subrec->myip = myip; subrec->type = type; subrec->nmb_sock = nmb_sock; subrec->nmb_bcast = nmb_bcast; subrec->dgram_sock = dgram_sock; subrec->dgram_bcast = dgram_bcast; return subrec; failed: SAFE_FREE(subrec); if (nmb_sock != -1) { close(nmb_sock); } if (nmb_bcast != -1) { close(nmb_bcast); } if (dgram_sock != -1) { close(dgram_sock); } if (dgram_bcast != -1) { close(dgram_bcast); } return NULL; }
struct test_join *torture_create_testuser(struct torture_context *torture, const char *username, const char *domain, uint16_t acct_type, const char **random_password) { NTSTATUS status; struct samr_Connect c; struct samr_CreateUser2 r; struct samr_OpenDomain o; struct samr_LookupDomain l; struct dom_sid2 *sid = NULL; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; struct samr_SetUserInfo s; union samr_UserInfo u; struct policy_handle handle; struct policy_handle domain_handle; uint32_t access_granted; uint32_t rid; DATA_BLOB session_key; struct lsa_String name; int policy_min_pw_len = 0; struct test_join *join; char *random_pw; const char *dc_binding = torture_setting_string(torture, "dc_binding", NULL); join = talloc(NULL, struct test_join); if (join == NULL) { return NULL; } ZERO_STRUCTP(join); printf("Connecting to SAMR\n"); if (dc_binding) { status = dcerpc_pipe_connect(join, &join->p, dc_binding, &ndr_table_samr, cmdline_credentials, NULL, torture->lp_ctx); } else { status = torture_rpc_connection(torture, &join->p, &ndr_table_samr); } if (!NT_STATUS_IS_OK(status)) { return NULL; } c.in.system_name = NULL; c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; c.out.connect_handle = &handle; status = dcerpc_samr_Connect(join->p, join, &c); if (!NT_STATUS_IS_OK(status)) { const char *errstr = nt_errstr(status); if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { errstr = dcerpc_errstr(join, join->p->last_fault_code); } printf("samr_Connect failed - %s\n", errstr); return NULL; } printf("Opening domain %s\n", domain); name.string = domain; l.in.connect_handle = &handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain(join->p, join, &l); if (!NT_STATUS_IS_OK(status)) { printf("LookupDomain failed - %s\n", nt_errstr(status)); goto failed; } talloc_steal(join, *l.out.sid); join->dom_sid = *l.out.sid; join->dom_netbios_name = talloc_strdup(join, domain); if (!join->dom_netbios_name) goto failed; o.in.connect_handle = &handle; o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; o.in.sid = *l.out.sid; o.out.domain_handle = &domain_handle; status = dcerpc_samr_OpenDomain(join->p, join, &o); if (!NT_STATUS_IS_OK(status)) { printf("OpenDomain failed - %s\n", nt_errstr(status)); goto failed; } printf("Creating account %s\n", username); again: name.string = username; r.in.domain_handle = &domain_handle; r.in.account_name = &name; r.in.acct_flags = acct_type; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.user_handle = &join->user_handle; r.out.access_granted = &access_granted; r.out.rid = &rid; status = dcerpc_samr_CreateUser2(join->p, join, &r); if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { status = DeleteUser_byname(join->p, join, &domain_handle, name.string); if (NT_STATUS_IS_OK(status)) { goto again; } } if (!NT_STATUS_IS_OK(status)) { printf("CreateUser2 failed - %s\n", nt_errstr(status)); goto failed; } join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid); pwp.in.user_handle = &join->user_handle; pwp.out.info = &info; status = dcerpc_samr_GetUserPwInfo(join->p, join, &pwp); if (NT_STATUS_IS_OK(status)) { policy_min_pw_len = pwp.out.info->min_password_length; } random_pw = generate_random_str(join, MAX(8, policy_min_pw_len)); printf("Setting account password '%s'\n", random_pw); ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 24; encode_pw_buffer(u.info24.password.data, random_pw, STR_UNICODE); u.info24.password_expired = 0; status = dcerpc_fetch_session_key(join->p, &session_key); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); torture_leave_domain(torture, join); goto failed; } arcfour_crypt_blob(u.info24.password.data, 516, &session_key); status = dcerpc_samr_SetUserInfo(join->p, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 21; u.info21.acct_flags = acct_type | ACB_PWNOEXP; u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME; u.info21.comment.string = talloc_asprintf(join, "Tortured by Samba4: %s", timestring(join, time(NULL))); u.info21.full_name.string = talloc_asprintf(join, "Torture account for Samba4: %s", timestring(join, time(NULL))); u.info21.description.string = talloc_asprintf(join, "Samba4 torture account created by host %s: %s", lp_netbios_name(torture->lp_ctx), timestring(join, time(NULL))); printf("Resetting ACB flags, force pw change time\n"); status = dcerpc_samr_SetUserInfo(join->p, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } if (random_password) { *random_password = random_pw; } return join; failed: torture_leave_domain(torture, join); return NULL; }
static enum ndr_err_code ndr_pull_frsapi_IsPathReplicated(struct ndr_pull *ndr, int flags, struct frsapi_IsPathReplicated *r) { uint32_t _ptr_path; uint32_t size_path_1 = 0; uint32_t length_path_1 = 0; TALLOC_CTX *_mem_save_path_0; TALLOC_CTX *_mem_save_replicated_0; TALLOC_CTX *_mem_save_primary_0; TALLOC_CTX *_mem_save_root_0; TALLOC_CTX *_mem_save_replica_set_guid_0; if (flags & NDR_IN) { ZERO_STRUCT(r->out); NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_path)); if (_ptr_path) { NDR_PULL_ALLOC(ndr, r->in.path); } else { r->in.path = NULL; } if (r->in.path) { _mem_save_path_0 = NDR_PULL_GET_MEM_CTX(ndr); NDR_PULL_SET_MEM_CTX(ndr, r->in.path, 0); NDR_CHECK(ndr_pull_array_size(ndr, &r->in.path)); NDR_CHECK(ndr_pull_array_length(ndr, &r->in.path)); size_path_1 = ndr_get_array_size(ndr, &r->in.path); length_path_1 = ndr_get_array_length(ndr, &r->in.path); if (length_path_1 > size_path_1) { return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed array length %u", size_path_1, length_path_1); } NDR_CHECK(ndr_check_string_terminator(ndr, length_path_1, sizeof(uint16_t))); NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->in.path, length_path_1, sizeof(uint16_t), CH_UTF16)); NDR_PULL_SET_MEM_CTX(ndr, _mem_save_path_0, 0); } NDR_CHECK(ndr_pull_frsapi_ReplicaSetType(ndr, NDR_SCALARS, &r->in.replica_set_type)); NDR_PULL_ALLOC(ndr, r->out.replicated); ZERO_STRUCTP(r->out.replicated); NDR_PULL_ALLOC(ndr, r->out.primary); ZERO_STRUCTP(r->out.primary); NDR_PULL_ALLOC(ndr, r->out.root); ZERO_STRUCTP(r->out.root); NDR_PULL_ALLOC(ndr, r->out.replica_set_guid); ZERO_STRUCTP(r->out.replica_set_guid); } if (flags & NDR_OUT) { if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_PULL_ALLOC(ndr, r->out.replicated); } _mem_save_replicated_0 = NDR_PULL_GET_MEM_CTX(ndr); NDR_PULL_SET_MEM_CTX(ndr, r->out.replicated, LIBNDR_FLAG_REF_ALLOC); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.replicated)); NDR_PULL_SET_MEM_CTX(ndr, _mem_save_replicated_0, LIBNDR_FLAG_REF_ALLOC); if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_PULL_ALLOC(ndr, r->out.primary); } _mem_save_primary_0 = NDR_PULL_GET_MEM_CTX(ndr); NDR_PULL_SET_MEM_CTX(ndr, r->out.primary, LIBNDR_FLAG_REF_ALLOC); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.primary)); NDR_PULL_SET_MEM_CTX(ndr, _mem_save_primary_0, LIBNDR_FLAG_REF_ALLOC); if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_PULL_ALLOC(ndr, r->out.root); } _mem_save_root_0 = NDR_PULL_GET_MEM_CTX(ndr); NDR_PULL_SET_MEM_CTX(ndr, r->out.root, LIBNDR_FLAG_REF_ALLOC); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, r->out.root)); NDR_PULL_SET_MEM_CTX(ndr, _mem_save_root_0, LIBNDR_FLAG_REF_ALLOC); if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_PULL_ALLOC(ndr, r->out.replica_set_guid); } _mem_save_replica_set_guid_0 = NDR_PULL_GET_MEM_CTX(ndr); NDR_PULL_SET_MEM_CTX(ndr, r->out.replica_set_guid, LIBNDR_FLAG_REF_ALLOC); NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, r->out.replica_set_guid)); NDR_PULL_SET_MEM_CTX(ndr, _mem_save_replica_set_guid_0, LIBNDR_FLAG_REF_ALLOC); NDR_CHECK(ndr_pull_WERROR(ndr, NDR_SCALARS, &r->out.result)); } return NDR_ERR_SUCCESS; }
static bool smb_raw_query_posix_whoami(void *mem_ctx, struct torture_context *torture, struct smbcli_state *cli, struct smb_whoami *whoami, unsigned max_data) { struct smb_trans2 tp; NTSTATUS status; size_t offset; int i; uint16_t setup = TRANSACT2_QFSINFO; uint16_t info_level; ZERO_STRUCTP(whoami); tp.in.max_setup = 0; tp.in.flags = 0; tp.in.timeout = 0; tp.in.setup_count = 1; tp.in.max_param = 10; tp.in.max_data = (uint16_t)max_data; tp.in.setup = &setup; tp.in.trans_name = NULL; SSVAL(&info_level, 0, SMB_QFS_POSIX_WHOAMI); tp.in.params = data_blob_talloc(mem_ctx, &info_level, 2); tp.in.data = data_blob_talloc(mem_ctx, NULL, 0); status = smb_raw_trans2(cli->tree, mem_ctx, &tp); torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK, "doing SMB_QFS_POSIX_WHOAMI"); /* Make sure we got back all the required fields. */ torture_assert(torture, tp.out.params.length == 0, "trans2 params should be empty"); torture_assert(torture, tp.out.data.length >= WHOAMI_REQUIRED_SIZE, "checking for required response fields"); whoami->mapping_flags = IVAL(tp.out.data.data, 0); whoami->mapping_mask = IVAL(tp.out.data.data, 4); whoami->server_uid = BVAL(tp.out.data.data, 8); whoami->server_gid = BVAL(tp.out.data.data, 16); whoami->num_gids = IVAL(tp.out.data.data, 24); whoami->num_sids = IVAL(tp.out.data.data, 28); whoami->num_sid_bytes = IVAL(tp.out.data.data, 32); whoami->reserved = IVAL(tp.out.data.data, 36); /* The GID list and SID list are optional, depending on the count * and length fields. */ if (whoami->num_sids != 0) { torture_assert(torture, whoami->num_sid_bytes != 0, "SID count does not match byte count"); } printf("\tmapping_flags=0x%08x mapping_mask=0x%08x\n", whoami->mapping_flags, whoami->mapping_mask); printf("\tserver UID=%llu GID=%llu\n", (unsigned long long)whoami->server_uid, (unsigned long long)whoami->server_gid); printf("\t%u GIDs, %u SIDs, %u SID bytes\n", whoami->num_gids, whoami->num_sids, whoami->num_sid_bytes); offset = WHOAMI_REQUIRED_SIZE; torture_assert_int_equal(torture, whoami->reserved, 0, "invalid reserved field"); if (tp.out.data.length == offset) { /* No SIDs or GIDs returned */ torture_assert_int_equal(torture, whoami->num_gids, 0, "invalid GID count"); torture_assert_int_equal(torture, whoami->num_sids, 0, "invalid SID count"); torture_assert_int_equal(torture, whoami->num_sid_bytes, 0, "invalid SID byte count"); return true; } if (whoami->num_gids != 0) { int remain = tp.out.data.length - offset; int gid_bytes = whoami->num_gids * 8; if (whoami->num_sids == 0) { torture_assert_int_equal(torture, remain, gid_bytes, "GID count does not match data length"); } else { torture_assert(torture, remain > gid_bytes, "invalid GID count"); } whoami->gid_list = talloc_array(mem_ctx, uint64_t, whoami->num_gids); torture_assert(torture, whoami->gid_list != NULL, "out of memory"); torture_comment(torture, "\tGIDs:\n"); for (i = 0; i < whoami->num_gids; ++i) { whoami->gid_list[i] = BVAL(tp.out.data.data, offset); offset += 8; torture_comment(torture, "\t\t%u\n", (unsigned int)whoami->gid_list[i]); } } /* Check if there should be data left for the SID list. */ if (tp.out.data.length == offset) { torture_assert_int_equal(torture, whoami->num_sids, 0, "invalid SID count"); return true; } /* All the remaining bytes must be the SID list. */ torture_assert_int_equal(torture, whoami->num_sid_bytes, (tp.out.data.length - offset), "invalid SID byte count"); if (whoami->num_sids != 0) { whoami->sid_list = talloc_array(mem_ctx, struct dom_sid *, whoami->num_sids); torture_assert(torture, whoami->sid_list != NULL, "out of memory"); torture_comment(torture, "\tSIDs:\n"); for (i = 0; i < whoami->num_sids; ++i) { if (!whoami_sid_parse(mem_ctx, torture, &tp.out.data, &offset, &whoami->sid_list[i])) { return false; } torture_comment(torture, "\t\t%s\n", dom_sid_string(torture, whoami->sid_list[i])); } }
static NTSTATUS find_forced_group(BOOL force_user, int snum, const char *username, DOM_SID *pgroup_sid, gid_t *pgid) { NTSTATUS result = NT_STATUS_NO_SUCH_GROUP; TALLOC_CTX *mem_ctx; DOM_SID group_sid; enum lsa_SidType type; char *groupname; BOOL user_must_be_member = False; gid_t gid; ZERO_STRUCTP(pgroup_sid); *pgid = (gid_t)-1; mem_ctx = talloc_new(NULL); if (mem_ctx == NULL) { DEBUG(0, ("talloc_new failed\n")); return NT_STATUS_NO_MEMORY; } groupname = talloc_strdup(mem_ctx, lp_force_group(snum)); if (groupname == NULL) { DEBUG(1, ("talloc_strdup failed\n")); result = NT_STATUS_NO_MEMORY; goto done; } if (groupname[0] == '+') { user_must_be_member = True; groupname += 1; } groupname = talloc_string_sub(mem_ctx, groupname, "%S", lp_servicename(snum)); if (!lookup_name_smbconf(mem_ctx, groupname, LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, NULL, NULL, &group_sid, &type)) { DEBUG(10, ("lookup_name_smbconf(%s) failed\n", groupname)); goto done; } if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) { DEBUG(10, ("%s is a %s, not a group\n", groupname, sid_type_lookup(type))); goto done; } if (!sid_to_gid(&group_sid, &gid)) { DEBUG(10, ("sid_to_gid(%s) for %s failed\n", sid_string_static(&group_sid), groupname)); goto done; } /* * If the user has been forced and the forced group starts with a '+', * then we only set the group to be the forced group if the forced * user is a member of that group. Otherwise, the meaning of the '+' * would be ignored. */ if (force_user && user_must_be_member) { if (user_in_group_sid(username, &group_sid)) { sid_copy(pgroup_sid, &group_sid); *pgid = gid; DEBUG(3,("Forced group %s for member %s\n", groupname, username)); } else { DEBUG(0,("find_forced_group: forced user %s is not a member " "of forced group %s. Disallowing access.\n", username, groupname )); result = NT_STATUS_MEMBER_NOT_IN_GROUP; goto done; } } else { sid_copy(pgroup_sid, &group_sid); *pgid = gid; DEBUG(3,("Forced group %s\n", groupname)); } result = NT_STATUS_OK; done: TALLOC_FREE(mem_ctx); return result; }
struct test_join *torture_create_testuser_max_pwlen(struct torture_context *torture, const char *username, const char *domain, uint16_t acct_type, const char **random_password, int max_pw_len) { NTSTATUS status; struct samr_Connect c; struct samr_CreateUser2 r; struct samr_OpenDomain o; struct samr_LookupDomain l; struct dom_sid2 *sid = NULL; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; struct samr_SetUserInfo s; union samr_UserInfo u; struct policy_handle handle; uint32_t access_granted; uint32_t rid; DATA_BLOB session_key; struct lsa_String name; int policy_min_pw_len = 0; struct test_join *join; char *random_pw; const char *dc_binding = torture_setting_string(torture, "dc_binding", NULL); struct dcerpc_binding_handle *b = NULL; join = talloc(NULL, struct test_join); if (join == NULL) { return NULL; } ZERO_STRUCTP(join); printf("Connecting to SAMR\n"); if (dc_binding) { status = dcerpc_pipe_connect(join, &join->p, dc_binding, &ndr_table_samr, cmdline_credentials, NULL, torture->lp_ctx); } else { status = torture_rpc_connection(torture, &join->p, &ndr_table_samr); } if (!NT_STATUS_IS_OK(status)) { return NULL; } b = join->p->binding_handle; c.in.system_name = NULL; c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; c.out.connect_handle = &handle; status = dcerpc_samr_Connect_r(b, join, &c); if (!NT_STATUS_IS_OK(status)) { const char *errstr = nt_errstr(status); printf("samr_Connect failed - %s\n", errstr); return NULL; } if (!NT_STATUS_IS_OK(c.out.result)) { const char *errstr = nt_errstr(c.out.result); printf("samr_Connect failed - %s\n", errstr); return NULL; } if (domain) { printf("Opening domain %s\n", domain); name.string = domain; l.in.connect_handle = &handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain_r(b, join, &l); if (!NT_STATUS_IS_OK(status)) { printf("LookupDomain failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(l.out.result)) { printf("LookupDomain failed - %s\n", nt_errstr(l.out.result)); goto failed; } } else { struct samr_EnumDomains e; uint32_t resume_handle = 0, num_entries; struct samr_SamArray *sam; int i; e.in.connect_handle = &handle; e.in.buf_size = (uint32_t)-1; e.in.resume_handle = &resume_handle; e.out.sam = &sam; e.out.num_entries = &num_entries; e.out.resume_handle = &resume_handle; status = dcerpc_samr_EnumDomains_r(b, join, &e); if (!NT_STATUS_IS_OK(status)) { printf("EnumDomains failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(e.out.result)) { printf("EnumDomains failed - %s\n", nt_errstr(e.out.result)); goto failed; } if ((num_entries != 2) || (sam && sam->count != 2)) { printf("unexpected number of domains\n"); goto failed; } for (i=0; i < 2; i++) { if (!strequal(sam->entries[i].name.string, "builtin")) { domain = sam->entries[i].name.string; break; } } if (domain) { printf("Opening domain %s\n", domain); name.string = domain; l.in.connect_handle = &handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain_r(b, join, &l); if (!NT_STATUS_IS_OK(status)) { printf("LookupDomain failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(l.out.result)) { printf("LookupDomain failed - %s\n", nt_errstr(l.out.result)); goto failed; } } else { printf("cannot proceed without domain name\n"); goto failed; } } talloc_steal(join, *l.out.sid); join->dom_sid = *l.out.sid; join->dom_netbios_name = talloc_strdup(join, domain); if (!join->dom_netbios_name) goto failed; o.in.connect_handle = &handle; o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; o.in.sid = *l.out.sid; o.out.domain_handle = &join->domain_handle; status = dcerpc_samr_OpenDomain_r(b, join, &o); if (!NT_STATUS_IS_OK(status)) { printf("OpenDomain failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(o.out.result)) { printf("OpenDomain failed - %s\n", nt_errstr(o.out.result)); goto failed; } printf("Creating account %s\n", username); again: name.string = username; r.in.domain_handle = &join->domain_handle; r.in.account_name = &name; r.in.acct_flags = acct_type; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.user_handle = &join->user_handle; r.out.access_granted = &access_granted; r.out.rid = &rid; status = dcerpc_samr_CreateUser2_r(b, join, &r); if (!NT_STATUS_IS_OK(status)) { printf("CreateUser2 failed - %s\n", nt_errstr(status)); goto failed; } if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) { status = DeleteUser_byname(b, join, &join->domain_handle, name.string); if (NT_STATUS_IS_OK(status)) { goto again; } } if (!NT_STATUS_IS_OK(r.out.result)) { printf("CreateUser2 failed - %s\n", nt_errstr(r.out.result)); goto failed; } join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid); pwp.in.user_handle = &join->user_handle; pwp.out.info = &info; status = dcerpc_samr_GetUserPwInfo_r(b, join, &pwp); if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(pwp.out.result)) { policy_min_pw_len = pwp.out.info->min_password_length; } random_pw = generate_random_password(join, MAX(8, policy_min_pw_len), max_pw_len); printf("Setting account password '%s'\n", random_pw); ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 24; encode_pw_buffer(u.info24.password.data, random_pw, STR_UNICODE); u.info24.password_expired = 0; status = dcerpc_fetch_session_key(join->p, &session_key); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo level %u - no session key - %s\n", s.in.level, nt_errstr(status)); torture_leave_domain(torture, join); goto failed; } arcfour_crypt_blob(u.info24.password.data, 516, &session_key); status = dcerpc_samr_SetUserInfo_r(b, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(s.out.result)) { printf("SetUserInfo failed - %s\n", nt_errstr(s.out.result)); goto failed; } ZERO_STRUCT(u); s.in.user_handle = &join->user_handle; s.in.info = &u; s.in.level = 21; u.info21.acct_flags = acct_type | ACB_PWNOEXP; u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME; u.info21.comment.string = talloc_asprintf(join, "Tortured by Samba4: %s", timestring(join, time(NULL))); u.info21.full_name.string = talloc_asprintf(join, "Torture account for Samba4: %s", timestring(join, time(NULL))); u.info21.description.string = talloc_asprintf(join, "Samba4 torture account created by host %s: %s", lpcfg_netbios_name(torture->lp_ctx), timestring(join, time(NULL))); printf("Resetting ACB flags, force pw change time\n"); status = dcerpc_samr_SetUserInfo_r(b, join, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo failed - %s\n", nt_errstr(status)); goto failed; } if (!NT_STATUS_IS_OK(s.out.result)) { printf("SetUserInfo failed - %s\n", nt_errstr(s.out.result)); goto failed; } if (random_password) { *random_password = random_pw; } return join; failed: torture_leave_domain(torture, join); return NULL; }
struct tdb_print_db *get_print_db_byname(const char *printername) { struct tdb_print_db *p = NULL, *last_entry = NULL; size_t num_open = 0; char *printdb_path = NULL; bool done_become_root = False; char *print_cache_path; int ret; SMB_ASSERT(printername != NULL); for (p = print_db_head, last_entry = print_db_head; p; p = p->next) { /* Ensure the list terminates... JRA. */ SMB_ASSERT(p->next != print_db_head); if (p->tdb && strequal(p->printer_name, printername)) { DLIST_PROMOTE(print_db_head, p); p->ref_count++; return p; } num_open++; last_entry = p; } /* Not found. */ if (num_open >= MAX_PRINT_DBS_OPEN) { /* Try and recycle the last entry. */ if (print_db_head && last_entry) { DLIST_PROMOTE(print_db_head, last_entry); } for (p = print_db_head; p; p = p->next) { if (p->ref_count) continue; if (p->tdb) { if (tdb_close(p->tdb)) { DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n", p->printer_name )); return NULL; } } p->tdb = NULL; p->ref_count = 0; memset(p->printer_name, '\0', sizeof(p->printer_name)); break; } if (p && print_db_head) { DLIST_PROMOTE(print_db_head, p); p = print_db_head; } } if (!p) { /* Create one. */ p = SMB_MALLOC_P(struct tdb_print_db); if (!p) { DEBUG(0,("get_print_db: malloc fail !\n")); return NULL; } ZERO_STRUCTP(p); DLIST_ADD(print_db_head, p); }
struct cli_state *cli_initialise(struct cli_state *cli) { BOOL alloced_cli = False; /* Check the effective uid - make sure we are not setuid */ if (is_setuid_root()) { DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n")); return NULL; } if (!cli) { cli = (struct cli_state *)malloc(sizeof(*cli)); if (!cli) return NULL; ZERO_STRUCTP(cli); alloced_cli = True; } if (cli->initialised) cli_close_connection(cli); ZERO_STRUCTP(cli); cli->port = 0; cli->fd = -1; cli->cnum = -1; cli->pid = (uint16)sys_getpid(); cli->mid = 1; cli->vuid = UID_FIELD_INVALID; cli->protocol = PROTOCOL_NT1; cli->timeout = 20000; /* Timeout is in milliseconds. */ cli->bufsize = CLI_BUFFER_SIZE+4; cli->max_xmit = cli->bufsize; cli->outbuf = (char *)malloc(cli->bufsize); cli->inbuf = (char *)malloc(cli->bufsize); cli->oplock_handler = cli_oplock_ack; /* Set the CLI_FORCE_DOSERR environment variable to test client routines using DOS errors instead of STATUS32 ones. This intended only as a temporary hack. */ if (getenv("CLI_FORCE_DOSERR")) cli->force_dos_errors = True; if (!cli->outbuf || !cli->inbuf) goto error; if ((cli->mem_ctx = talloc_init()) == NULL) goto error; memset(cli->outbuf, 0, cli->bufsize); memset(cli->inbuf, 0, cli->bufsize); cli->nt_pipe_fnum = 0; cli->initialised = 1; cli->allocated = alloced_cli; return cli; /* Clean up after malloc() error */ error: SAFE_FREE(cli->inbuf); SAFE_FREE(cli->outbuf); if (alloced_cli) SAFE_FREE(cli); return NULL; }
/* * do a domain join using DCERPC/SAMR calls * - connect to the LSA pipe, to try and find out information about the domain * - create a secondary connection to SAMR pipe * - do a samr_Connect to get a policy handle * - do a samr_LookupDomain to get the domain sid * - do a samr_OpenDomain to get a domain handle * - do a samr_CreateAccount to try and get a new account * * If that fails, do: * - do a samr_LookupNames to get the users rid * - do a samr_OpenUser to get a user handle * - potentially delete and recreate the user * - assert the account is of the right type with samrQueryUserInfo * * - call libnet_SetPassword_samr_handle to set the password, * and pass a samr_UserInfo21 struct to set full_name and the account flags * * - do some ADS specific things when we join as Domain Controller, * look at libnet_joinADSDomain() for the details */ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *r) { TALLOC_CTX *tmp_ctx; NTSTATUS status, cu_status; struct libnet_RpcConnect *connect_with_info; struct dcerpc_pipe *samr_pipe; struct samr_Connect sc; struct policy_handle p_handle; struct samr_OpenDomain od; struct policy_handle d_handle; struct samr_LookupNames ln; struct samr_Ids rids, types; struct samr_OpenUser ou; struct samr_CreateUser2 cu; struct policy_handle *u_handle = NULL; struct samr_QueryUserInfo qui; union samr_UserInfo *uinfo; struct samr_UserInfo21 u_info21; union libnet_SetPassword r2; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; struct lsa_String samr_account_name; uint32_t acct_flags, old_acct_flags; uint32_t rid, access_granted; int policy_min_pw_len = 0; struct dom_sid *account_sid = NULL; const char *password_str = NULL; r->out.error_string = NULL; r2.samr_handle.out.error_string = NULL; tmp_ctx = talloc_named(mem_ctx, 0, "libnet_Join temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } u_handle = talloc(tmp_ctx, struct policy_handle); if (!u_handle) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } connect_with_info = talloc_zero(tmp_ctx, struct libnet_RpcConnect); if (!connect_with_info) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* prepare connect to the SAMR pipe of PDC */ if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { connect_with_info->in.binding = NULL; connect_with_info->in.name = r->in.domain_name; } else { connect_with_info->in.binding = r->in.binding; connect_with_info->in.name = NULL; } /* This level makes a connection to the LSA pipe on the way, * to get some useful bits of information about the domain */ connect_with_info->level = LIBNET_RPC_CONNECT_DC_INFO; connect_with_info->in.dcerpc_iface = &ndr_table_samr; /* establish the SAMR connection */ status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info); if (!NT_STATUS_IS_OK(status)) { if (r->in.binding) { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of DC %s failed: %s", r->in.binding, connect_with_info->out.error_string); } else { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of PDC for %s failed: %s", r->in.domain_name, connect_with_info->out.error_string); } talloc_free(tmp_ctx); return status; } samr_pipe = connect_with_info->out.dcerpc_pipe; status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe, connect_with_info->out.dcerpc_pipe->binding, &ndr_table_samr, ctx->cred, ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "SAMR bind failed: %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* prepare samr_Connect */ ZERO_STRUCT(p_handle); sc.in.system_name = NULL; sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; sc.out.connect_handle = &p_handle; /* 2. do a samr_Connect to get a policy handle */ status = dcerpc_samr_Connect_r(samr_pipe->binding_handle, tmp_ctx, &sc); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sc.out.result)) { status = sc.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_Connect failed: %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* If this is a connection on ncacn_ip_tcp to Win2k3 SP1, we don't get back this useful info */ if (!connect_with_info->out.domain_name) { if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, r->in.domain_name); } else { /* Bugger, we just lost our way to automatically find the domain name */ connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lpcfg_workgroup(ctx->lp_ctx)); connect_with_info->out.realm = talloc_strdup(tmp_ctx, lpcfg_realm(ctx->lp_ctx)); } } /* Perhaps we didn't get a SID above, because we are against ncacn_ip_tcp */ if (!connect_with_info->out.domain_sid) { struct lsa_String name; struct samr_LookupDomain l; struct dom_sid2 *sid = NULL; name.string = connect_with_info->out.domain_name; l.in.connect_handle = &p_handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain_r(samr_pipe->binding_handle, tmp_ctx, &l); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(l.out.result)) { status = l.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "SAMR LookupDomain failed: %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } connect_with_info->out.domain_sid = *l.out.sid; } /* prepare samr_OpenDomain */ ZERO_STRUCT(d_handle); od.in.connect_handle = &p_handle; od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; od.in.sid = connect_with_info->out.domain_sid; od.out.domain_handle = &d_handle; /* do a samr_OpenDomain to get a domain handle */ status = dcerpc_samr_OpenDomain_r(samr_pipe->binding_handle, tmp_ctx, &od); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(od.out.result)) { status = od.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_OpenDomain for [%s] failed: %s", dom_sid_string(tmp_ctx, connect_with_info->out.domain_sid), nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* prepare samr_CreateUser2 */ ZERO_STRUCTP(u_handle); cu.in.domain_handle = &d_handle; cu.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; samr_account_name.string = r->in.account_name; cu.in.account_name = &samr_account_name; cu.in.acct_flags = r->in.acct_type; cu.out.user_handle = u_handle; cu.out.rid = &rid; cu.out.access_granted = &access_granted; /* do a samr_CreateUser2 to get an account handle, or an error */ cu_status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu); if (NT_STATUS_IS_OK(cu_status) && !NT_STATUS_IS_OK(cu.out.result)) { cu_status = cu.out.result; } status = cu_status; if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { /* prepare samr_LookupNames */ ln.in.domain_handle = &d_handle; ln.in.num_names = 1; ln.in.names = talloc_array(tmp_ctx, struct lsa_String, 1); ln.out.rids = &rids; ln.out.types = &types; if (!ln.in.names) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ln.in.names[0].string = r->in.account_name; /* 5. do a samr_LookupNames to get the users rid */ status = dcerpc_samr_LookupNames_r(samr_pipe->binding_handle, tmp_ctx, &ln); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ln.out.result)) { status = ln.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* check if we got one RID for the user */ if (ln.out.rids->count != 1) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] returns %d RIDs", r->in.account_name, ln.out.rids->count); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* prepare samr_OpenUser */ ZERO_STRUCTP(u_handle); ou.in.domain_handle = &d_handle; ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; ou.in.rid = ln.out.rids->ids[0]; rid = ou.in.rid; ou.out.user_handle = u_handle; /* 6. do a samr_OpenUser to get a user handle */ status = dcerpc_samr_OpenUser_r(samr_pipe->binding_handle, tmp_ctx, &ou); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ou.out.result)) { status = ou.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_OpenUser for [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } if (r->in.recreate_account) { struct samr_DeleteUser d; d.in.user_handle = u_handle; d.out.user_handle = u_handle; status = dcerpc_samr_DeleteUser_r(samr_pipe->binding_handle, mem_ctx, &d); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(d.out.result)) { status = d.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_DeleteUser (for recreate) of [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* We want to recreate, so delete and another samr_CreateUser2 */ /* &cu filled in above */ status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(cu.out.result)) { status = cu.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_CreateUser2 (recreate) for [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } } else if (!NT_STATUS_IS_OK(status)) {
sftp_client_message sftp_get_client_message(sftp_session sftp) { ssh_session session = sftp->session; sftp_packet packet; sftp_client_message msg; ssh_buffer payload; int rc; msg = malloc(sizeof (struct sftp_client_message_struct)); if (msg == NULL) { ssh_set_error_oom(session); return NULL; } ZERO_STRUCTP(msg); packet = sftp_packet_read(sftp); if (packet == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } payload = packet->payload; msg->type = packet->type; msg->sftp = sftp; /* take a copy of the whole packet */ msg->complete_message = ssh_buffer_new(); ssh_buffer_add_data(msg->complete_message, ssh_buffer_get(payload), ssh_buffer_get_len(payload)); ssh_buffer_get_u32(payload, &msg->id); switch(msg->type) { case SSH_FXP_CLOSE: case SSH_FXP_READDIR: msg->handle = ssh_buffer_get_ssh_string(payload); if (msg->handle == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_READ: rc = ssh_buffer_unpack(payload, "Sqd", &msg->handle, &msg->offset, &msg->len); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_WRITE: rc = ssh_buffer_unpack(payload, "SqS", &msg->handle, &msg->offset, &msg->data); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_REMOVE: case SSH_FXP_RMDIR: case SSH_FXP_OPENDIR: case SSH_FXP_READLINK: case SSH_FXP_REALPATH: rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_RENAME: case SSH_FXP_SYMLINK: rc = ssh_buffer_unpack(payload, "sS", &msg->filename, &msg->data); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_MKDIR: case SSH_FXP_SETSTAT: rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_FSETSTAT: msg->handle = ssh_buffer_get_ssh_string(payload); if (msg->handle == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_LSTAT: case SSH_FXP_STAT: rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } if(sftp->version > 3) { ssh_buffer_unpack(payload, "d", &msg->flags); } break; case SSH_FXP_OPEN: rc = ssh_buffer_unpack(payload, "sd", &msg->filename, &msg->flags); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_FSTAT: rc = ssh_buffer_unpack(payload, "S", &msg->handle); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; default: ssh_set_error(sftp->session, SSH_FATAL, "Received unhandled sftp message %d", msg->type); sftp_client_message_free(msg); return NULL; } sftp_packet_free(packet); return msg; }
static WINBINDD_GR* string2group( char *string ) { static WINBINDD_GR grp; char *p, *str; char *fields[NUM_GRP_FIELDS]; int i; char **gr_members = NULL; int num_gr_members = 0; if ( !string ) return NULL; ZERO_STRUCTP( &grp ); DEBUG(10,("string2group: converting \"%s\"\n", string)); ZERO_STRUCT( fields ); for ( i=0, str=string; i<NUM_GRP_FIELDS-1; i++ ) { if ( !(p = strchr( str, ':' )) ) { DEBUG(0,("string2group: parsing failure\n")); return NULL; } *p = '\0'; if ( str ) fields[i] = str; str = p + 1; } /* group members */ if ( *str ) { /* we already know we have a non-empty string */ num_gr_members = count_chars(str, ',') + 1; /* if there was at least one comma, then there are n+1 members */ if ( num_gr_members ) { fstring buffer; gr_members = SMB_XMALLOC_ARRAY(char*, num_gr_members+1); i = 0; while ( next_token(&str, buffer, ",", sizeof(buffer)) && i<num_gr_members ) { gr_members[i++] = smb_xstrdup(buffer); } gr_members[i] = NULL; } } /* copy fields */ fstrcpy( grp.gr_name, fields[0] ); fstrcpy( grp.gr_passwd, fields[1] ); grp.gr_gid = atoi( fields[2] ); grp.num_gr_mem = num_gr_members; grp.gr_mem = gr_members; /* last minute sanity checks */ if ( grp.gr_gid == 0 ) { DEBUG(0,("string2group: Failure! gid==%lu\n", (unsigned long)grp.gr_gid)); SAFE_FREE( gr_members ); return NULL; } DEBUG(10,("string2group: Success\n")); return &grp; }
struct tdb_print_db *get_print_db_byname(const char *printername) { struct tdb_print_db *p = NULL, *last_entry = NULL; int num_open = 0; pstring printdb_path; BOOL done_become_root = False; for (p = print_db_head, last_entry = print_db_head; p; p = p->next) { /* Ensure the list terminates... JRA. */ SMB_ASSERT(p->next != print_db_head); if (p->tdb && strequal(p->printer_name, printername)) { DLIST_PROMOTE(print_db_head, p); p->ref_count++; return p; } num_open++; last_entry = p; } /* Not found. */ if (num_open >= MAX_PRINT_DBS_OPEN) { /* Try and recycle the last entry. */ DLIST_PROMOTE(print_db_head, last_entry); for (p = print_db_head; p; p = p->next) { if (p->ref_count) continue; if (p->tdb) { if (tdb_close(print_db_head->tdb)) { DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n", print_db_head->printer_name )); return NULL; } } p->tdb = NULL; p->ref_count = 0; memset(p->printer_name, '\0', sizeof(p->printer_name)); break; } if (p) { DLIST_PROMOTE(print_db_head, p); p = print_db_head; } } if (!p) { /* Create one. */ p = (struct tdb_print_db *)malloc(sizeof(struct tdb_print_db)); if (!p) { DEBUG(0,("get_print_db: malloc fail !\n")); return NULL; } ZERO_STRUCTP(p); DLIST_ADD(print_db_head, p); } pstrcpy(printdb_path, lock_path("printing/")); pstrcat(printdb_path, printername); pstrcat(printdb_path, ".tdb"); if (geteuid() != 0) { become_root(); done_become_root = True; } p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); if (done_become_root) unbecome_root(); if (!p->tdb) { DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n", printdb_path )); DLIST_REMOVE(print_db_head, p); SAFE_FREE(p); return NULL; } fstrcpy(p->printer_name, printername); p->ref_count++; return p; }
static int server_set_kex(ssh_session session) { struct ssh_kex_struct *server = &session->next_crypto->server_kex; int i, j, rc; const char *wanted; char hostkeys[64] = {0}; enum ssh_keytypes_e keytype; size_t len; int ok; ZERO_STRUCTP(server); ok = ssh_get_random(server->cookie, 16, 0); if (!ok) { ssh_set_error(session, SSH_FATAL, "PRNG error"); return -1; } if (session->srv.ed25519_key != NULL) { snprintf(hostkeys, sizeof(hostkeys), "%s", ssh_key_type_to_char(ssh_key_type(session->srv.ed25519_key))); } #ifdef HAVE_ECC if (session->srv.ecdsa_key != NULL) { len = strlen(hostkeys); snprintf(hostkeys + len, sizeof(hostkeys) - len, ",%s", session->srv.ecdsa_key->type_c); } #endif #ifdef HAVE_DSA if (session->srv.dsa_key != NULL) { len = strlen(hostkeys); keytype = ssh_key_type(session->srv.dsa_key); snprintf(hostkeys + len, sizeof(hostkeys) - len, ",%s", ssh_key_type_to_char(keytype)); } #endif if (session->srv.rsa_key != NULL) { len = strlen(hostkeys); keytype = ssh_key_type(session->srv.rsa_key); snprintf(hostkeys + len, sizeof(hostkeys) - len, ",%s", ssh_key_type_to_char(keytype)); } if (strlen(hostkeys) == 0) { return -1; } rc = ssh_options_set_algo(session, SSH_HOSTKEYS, hostkeys[0] == ',' ? hostkeys + 1 : hostkeys); if (rc < 0) { return -1; } for (i = 0; i < 10; i++) { if ((wanted = session->opts.wanted_methods[i]) == NULL) { wanted = ssh_kex_get_supported_method(i); } server->methods[i] = strdup(wanted); if (server->methods[i] == NULL) { for (j = 0; j < i; j++) { SAFE_FREE(server->methods[j]); } return -1; } } return 0; }
SMBCFILE * SMBC_open_ctx(SMBCCTX *context, const char *fname, int flags, mode_t mode) { char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *workgroup = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; SMBCSRV *srv = NULL; SMBCFILE *file = NULL; uint16_t fd; uint16_t port = 0; NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return NULL; } if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } if (SMBC_parse_path(frame, context, fname, &workgroup, &server, &port, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } if (!user || user[0] == (char)0) { user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } } srv = SMBC_server(frame, context, True, server, port, share, &workgroup, &user, &password); if (!srv) { if (errno == EPERM) errno = EACCES; TALLOC_FREE(frame); return NULL; /* SMBC_server sets errno */ } /* Hmmm, the test for a directory is suspect here ... FIXME */ if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { status = NT_STATUS_OBJECT_PATH_INVALID; } else { file = SMB_MALLOC_P(SMBCFILE); if (!file) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } ZERO_STRUCTP(file); /*d_printf(">>>open: resolving %s\n", path);*/ status = cli_resolve_path( frame, "", context->internal->auth_info, srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; SAFE_FREE(file); TALLOC_FREE(frame); return NULL; } /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ status = cli_open(targetcli, targetpath, flags, context->internal->share_mode, &fd); if (!NT_STATUS_IS_OK(status)) { /* Handle the error ... */ SAFE_FREE(file); errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return NULL; } /* Fill in file struct */ file->cli_fd = fd; file->fname = SMB_STRDUP(fname); file->srv = srv; file->offset = 0; file->file = True; /* * targetcli is either equal to srv->cli or * is a subsidiary DFS connection. Either way * file->cli_fd belongs to it so we must cache * it for read/write/close, not re-resolve each time. * Re-resolving is both slow and incorrect. */ file->targetcli = targetcli; DLIST_ADD(context->internal->files, file); /* * If the file was opened in O_APPEND mode, all write * operations should be appended to the file. To do that, * though, using this protocol, would require a getattrE() * call for each and every write, to determine where the end * of the file is. (There does not appear to be an append flag * in the protocol.) Rather than add all of that overhead of * retrieving the current end-of-file offset prior to each * write operation, we'll assume that most append operations * will continuously write, so we'll just set the offset to * the end of the file now and hope that's adequate. * * Note to self: If this proves inadequate, and O_APPEND * should, in some cases, be forced for each write, add a * field in the context options structure, for * "strict_append_mode" which would select between the current * behavior (if FALSE) or issuing a getattrE() prior to each * write and forcing the write to the end of the file (if * TRUE). Adding that capability will likely require adding * an "append" flag into the _SMBCFILE structure to track * whether a file was opened in O_APPEND mode. -- djl */ if (flags & O_APPEND) { if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) { (void) SMBC_close_ctx(context, file); errno = ENXIO; TALLOC_FREE(frame); return NULL; } } TALLOC_FREE(frame); return file; } /* Check if opendir needed ... */ if (!NT_STATUS_IS_OK(status)) { int eno = 0; eno = SMBC_errno(context, srv->cli); file = smbc_getFunctionOpendir(context)(context, fname); if (!file) errno = eno; TALLOC_FREE(frame); return file; } errno = EINVAL; /* FIXME, correct errno ? */ TALLOC_FREE(frame); return NULL; }
NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u) { NTSTATUS status = NT_STATUS_OK; NET_USER_INFO_3 *usr_info = NULL; NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr; DOM_CRED srv_cred; UNISTR2 *uni_samlogon_user = NULL; UNISTR2 *uni_samlogon_domain = NULL; UNISTR2 *uni_samlogon_workstation = NULL; fstring nt_username, nt_domain, nt_workstation; auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; extern userdom_struct current_user_info; SAM_ACCOUNT *sampw; struct auth_context *auth_context = NULL; usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3)); if (!usr_info) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(usr_info); /* store the user information, if there is any. */ r_u->user = usr_info; r_u->switch_value = 0; /* indicates no info */ r_u->auth_resp = 1; /* authoritative response */ r_u->switch_value = 3; /* indicates type of validation user info */ if (!get_valid_user_struct(p->vuid)) return NT_STATUS_NO_SUCH_USER; if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) { /* 'server schannel = yes' should enforce use of schannel, the client did offer it in auth2, but obviously did not use it. */ return NT_STATUS_ACCESS_DENIED; } /* checks and updates credentials. creates reply credentials */ if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))) return NT_STATUS_INVALID_HANDLE; memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred)); r_u->buffer_creds = 1; /* yes, we have valid server credentials */ memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds)); /* find the username */ switch (q_u->sam_id.logon_level) { case INTERACTIVE_LOGON_TYPE: uni_samlogon_user = &ctr->auth.id1.uni_user_name; uni_samlogon_domain = &ctr->auth.id1.uni_domain_name; uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name; DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup())); break; case NET_LOGON_TYPE: uni_samlogon_user = &ctr->auth.id2.uni_user_name; uni_samlogon_domain = &ctr->auth.id2.uni_domain_name; uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name; DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup())); break; default: DEBUG(2,("SAM Logon: unsupported switch value\n")); return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0); rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0); rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0); DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain)); fstrcpy(current_user_info.smb_name, nt_username); sub_set_smb_name(nt_username); DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username)); status = NT_STATUS_OK; switch (ctr->switch_value) { case NET_LOGON_TYPE: { const char *wksname = nt_workstation; if (!NT_STATUS_IS_OK(status = make_auth_context_fixed(&auth_context, ctr->auth.id2.lm_chal))) { return status; } /* For a network logon, the workstation name comes in with two * backslashes in the front. Strip them if they are there. */ if (*wksname == '\\') wksname++; if (*wksname == '\\') wksname++; /* Standard challenge/response authenticaion */ if (!make_user_info_netlogon_network(&user_info, nt_username, nt_domain, wksname, ctr->auth.id2.lm_chal_resp.buffer, ctr->auth.id2.lm_chal_resp.str_str_len, ctr->auth.id2.nt_chal_resp.buffer, ctr->auth.id2.nt_chal_resp.str_str_len)) { status = NT_STATUS_NO_MEMORY; } break; } case INTERACTIVE_LOGON_TYPE: /* 'Interactive' autheticaion, supplies the password in its MD4 form, encrypted with the session key. We will convert this to chellange/responce for the auth subsystem to chew on */ { const uint8 *chal; if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) { return status; } chal = auth_context->get_ntlm_challenge(auth_context); if (!make_user_info_netlogon_interactive(&user_info, nt_username, nt_domain, nt_workstation, chal, ctr->auth.id1.lm_owf.data, ctr->auth.id1.nt_owf.data, p->dc.sess_key)) { status = NT_STATUS_NO_MEMORY; } break; } default: DEBUG(2,("SAM Logon: unsupported switch value\n")); return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ if ( NT_STATUS_IS_OK(status) ) { status = auth_context->check_ntlm_password(auth_context, user_info, &server_info); } (auth_context->free)(&auth_context); free_user_info(&user_info); DEBUG(5, ("_net_sam_logon: check_password returned status %s\n", nt_errstr(status))); /* Check account and password */ if (!NT_STATUS_IS_OK(status)) { free_server_info(&server_info); return status; } if (server_info->guest) { /* We don't like guest domain logons... */ DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n")); free_server_info(&server_info); return NT_STATUS_LOGON_FAILURE; } /* This is the point at which, if the login was successful, that the SAM Local Security Authority should record that the user is logged in to the domain. */ { DOM_GID *gids = NULL; const DOM_SID *user_sid = NULL; const DOM_SID *group_sid = NULL; DOM_SID domain_sid; uint32 user_rid, group_rid; int num_gids = 0; pstring my_name; fstring user_sid_string; fstring group_sid_string; uchar user_session_key[16]; uchar lm_session_key[16]; uchar netlogon_sess_key[16]; sampw = server_info->sam_account; /* set up pointer indicating user/password failed to be found */ usr_info->ptr_user_info = 0; user_sid = pdb_get_user_sid(sampw); group_sid = pdb_get_group_sid(sampw); sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &user_rid); if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) { DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid %s\n but group sid %s.\nThe conflicting domain portions are not supported for NETLOGON calls\n", pdb_get_domain(sampw), pdb_get_username(sampw), sid_to_string(user_sid_string, user_sid), sid_to_string(group_sid_string, group_sid))); return NT_STATUS_UNSUCCESSFUL; } pstrcpy(my_name, global_myname()); if (!NT_STATUS_IS_OK(status = nt_token_to_group_list(p->mem_ctx, &domain_sid, server_info->ptok, &num_gids, &gids))) { return status; } ZERO_STRUCT(netlogon_sess_key); memcpy(netlogon_sess_key, p->dc.sess_key, 8); if (server_info->user_session_key.length) { memcpy(user_session_key, server_info->user_session_key.data, MIN(sizeof(user_session_key), server_info->user_session_key.length)); SamOEMhash(user_session_key, netlogon_sess_key, 16); } if (server_info->lm_session_key.length) { memcpy(lm_session_key, server_info->lm_session_key.data, MIN(sizeof(lm_session_key), server_info->lm_session_key.length)); SamOEMhash(lm_session_key, netlogon_sess_key, 16); } ZERO_STRUCT(netlogon_sess_key); init_net_user_info3(p->mem_ctx, usr_info, user_rid, group_rid, pdb_get_username(sampw), pdb_get_fullname(sampw), pdb_get_homedir(sampw), pdb_get_dir_drive(sampw), pdb_get_logon_script(sampw), pdb_get_profile_path(sampw), pdb_get_logon_time(sampw), get_time_t_max(), get_time_t_max(), pdb_get_pass_last_set_time(sampw), pdb_get_pass_can_change_time(sampw), pdb_get_pass_must_change_time(sampw), 0, /* logon_count */ 0, /* bad_pw_count */ num_gids, /* uint32 num_groups */ gids , /* DOM_GID *gids */ 0x20 , /* uint32 user_flgs (?) */ server_info->user_session_key.length ? user_session_key : NULL, server_info->lm_session_key.length ? lm_session_key : NULL, my_name , /* char *logon_srv */ pdb_get_domain(sampw), &domain_sid, /* DOM_SID *dom_sid */ /* Should be users domain sid, not servers - for trusted domains */ NULL); /* char *other_sids */ ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); } free_server_info(&server_info); return status; }
int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name) { user_struct *vuser = NULL; /* Paranoia check. */ if(lp_security() == SEC_SHARE) { smb_panic("Tried to register uid in security=share\n"); } /* Limit allowed vuids to 16bits - VUID_OFFSET. */ if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) { data_blob_free(&session_key); return UID_FIELD_INVALID; } if((vuser = SMB_MALLOC_P(user_struct)) == NULL) { DEBUG(0,("Failed to malloc users struct!\n")); data_blob_free(&session_key); return UID_FIELD_INVALID; } ZERO_STRUCTP(vuser); /* Allocate a free vuid. Yes this is a linear search... :-) */ while( get_valid_user_struct(next_vuid) != NULL ) { next_vuid++; /* Check for vuid wrap. */ if (next_vuid == UID_FIELD_INVALID) next_vuid = VUID_OFFSET; } DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); vuser->vuid = next_vuid; if (!server_info) { /* * This happens in an unfinished NTLMSSP session setup. We * need to allocate a vuid between the first and second calls * to NTLMSSP. */ next_vuid++; num_validated_vuids++; vuser->server_info = NULL; DLIST_ADD(validated_users, vuser); return vuser->vuid; } /* the next functions should be done by a SID mapping system (SMS) as * the new real sam db won't have reference to unix uids or gids */ vuser->uid = server_info->uid; vuser->gid = server_info->gid; vuser->n_groups = server_info->n_groups; if (vuser->n_groups) { if (!(vuser->groups = (gid_t *)memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) { DEBUG(0,("register_vuid: failed to memdup " "vuser->groups\n")); data_blob_free(&session_key); free(vuser); TALLOC_FREE(server_info); return UID_FIELD_INVALID; } } vuser->guest = server_info->guest; fstrcpy(vuser->user.unix_name, server_info->unix_name); /* This is a potentially untrusted username */ alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", sizeof(vuser->user.smb_name)); fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account)); { /* Keep the homedir handy */ const char *homedir = pdb_get_homedir(server_info->sam_account); const char *logon_script = pdb_get_logon_script(server_info->sam_account); if (!IS_SAM_DEFAULT(server_info->sam_account, PDB_UNIXHOMEDIR)) { const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); if (unix_homedir) { vuser->unix_homedir = smb_xstrdup(unix_homedir); } } else { struct passwd *passwd = getpwnam_alloc(NULL, vuser->user.unix_name); if (passwd) { vuser->unix_homedir = smb_xstrdup(passwd->pw_dir); TALLOC_FREE(passwd); } } if (homedir) { vuser->homedir = smb_xstrdup(homedir); } if (logon_script) { vuser->logon_script = smb_xstrdup(logon_script); } } vuser->session_key = session_key; DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)vuser->uid, (unsigned int)vuser->gid, vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, vuser->guest )); DEBUG(3, ("User name: %s\tReal name: %s\n", vuser->user.unix_name, vuser->user.full_name)); if (server_info->ptok) { vuser->nt_user_token = dup_nt_token(NULL, server_info->ptok); } else { DEBUG(1, ("server_info does not contain a user_token - " "cannot continue\n")); TALLOC_FREE(server_info); data_blob_free(&session_key); SAFE_FREE(vuser->homedir); SAFE_FREE(vuser->unix_homedir); SAFE_FREE(vuser->logon_script); SAFE_FREE(vuser); return UID_FIELD_INVALID; } /* use this to keep tabs on all our info from the authentication */ vuser->server_info = server_info; DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n", (int)vuser->uid,vuser->user.unix_name, vuser->vuid)); next_vuid++; num_validated_vuids++; DLIST_ADD(validated_users, vuser); if (!session_claim(vuser)) { DEBUG(1, ("Failed to claim session for vuid=%d\n", vuser->vuid)); invalidate_vuid(vuser->vuid); return UID_FIELD_INVALID; } /* Register a home dir service for this user iff (a) This is not a guest connection, (b) we have a home directory defined (c) there s not an existing static share by that name If a share exists by this name (autoloaded or not) reuse it . */ vuser->homes_snum = -1; if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) { int servicenumber = lp_servicenumber(vuser->user.unix_name); if ( servicenumber == -1 ) { DEBUG(3, ("Adding homes service for user '%s' using " "home directory: '%s'\n", vuser->user.unix_name, vuser->unix_homedir)); vuser->homes_snum = add_home_service(vuser->user.unix_name, vuser->user.unix_name, vuser->unix_homedir); } else { DEBUG(3, ("Using static (or previously created) " "service for user '%s'; path = '%s'\n", vuser->user.unix_name, lp_pathname(servicenumber) )); vuser->homes_snum = servicenumber; } } if (srv_is_signing_negotiated() && !vuser->guest && !srv_signing_started()) { /* Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(vuser->session_key, response_blob); } /* fill in the current_user_info struct */ set_current_user_info( &vuser->user ); return vuser->vuid; }
/** * @brief Create a new ssh session. * * @returns A new ssh_session pointer, NULL on error. */ ssh_session ssh_new(void) { ssh_session session; char *id = NULL; int rc; session = malloc(sizeof (struct ssh_session_struct)); if (session == NULL) { return NULL; } ZERO_STRUCTP(session); session->next_crypto = crypto_new(); if (session->next_crypto == NULL) { goto err; } session->socket = ssh_socket_new(session); if (session->socket == NULL) { goto err; } session->out_buffer = ssh_buffer_new(); if (session->out_buffer == NULL) { goto err; } session->in_buffer=ssh_buffer_new(); if (session->in_buffer == NULL) { goto err; } session->alive = 0; session->auth_methods = 0; ssh_set_blocking(session, 1); session->maxchannel = FIRST_CHANNEL; #ifndef _WIN32 session->agent = ssh_agent_new(session); if (session->agent == NULL) { goto err; } #endif /* _WIN32 */ /* OPTIONS */ session->opts.StrictHostKeyChecking = 1; session->opts.port = 0; session->opts.fd = -1; session->opts.compressionlevel=7; session->opts.nodelay = 0; session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH | SSH_OPT_FLAG_PUBKEY_AUTH | SSH_OPT_FLAG_KBDINT_AUTH | SSH_OPT_FLAG_GSSAPI_AUTH; session->opts.identity = ssh_list_new(); if (session->opts.identity == NULL) { goto err; } id = strdup("%d/id_ed25519"); if (id == NULL) { goto err; } rc = ssh_list_append(session->opts.identity, id); if (rc == SSH_ERROR) { goto err; } #ifdef HAVE_ECC id = strdup("%d/id_ecdsa"); if (id == NULL) { goto err; } rc = ssh_list_append(session->opts.identity, id); if (rc == SSH_ERROR) { goto err; } #endif id = strdup("%d/id_rsa"); if (id == NULL) { goto err; } rc = ssh_list_append(session->opts.identity, id); if (rc == SSH_ERROR) { goto err; } #ifdef HAVE_DSA id = strdup("%d/id_dsa"); if (id == NULL) { goto err; } rc = ssh_list_append(session->opts.identity, id); if (rc == SSH_ERROR) { goto err; } #endif return session; err: free(id); ssh_free(session); return NULL; }
static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, struct spnego_negTokenInit *token) { ZERO_STRUCTP(token); asn1_start_tag(asn1, ASN1_CONTEXT(0)); asn1_start_tag(asn1, ASN1_SEQUENCE(0)); while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) { int i; uint8_t context; if (!asn1_peek_uint8(asn1, &context)) { asn1->has_error = true; break; } switch (context) { /* Read mechTypes */ case ASN1_CONTEXT(0): asn1_start_tag(asn1, ASN1_CONTEXT(0)); asn1_start_tag(asn1, ASN1_SEQUENCE(0)); token->mechTypes = talloc(NULL, const char *); for (i = 0; !asn1->has_error && 0 < asn1_tag_remaining(asn1); i++) { token->mechTypes = talloc_realloc(NULL, token->mechTypes, const char *, i+2); asn1_read_OID(asn1, token->mechTypes, token->mechTypes + i); } token->mechTypes[i] = NULL; asn1_end_tag(asn1); asn1_end_tag(asn1); break; /* Read reqFlags */ case ASN1_CONTEXT(1): asn1_start_tag(asn1, ASN1_CONTEXT(1)); asn1_read_Integer(asn1, &token->reqFlags); token->reqFlags |= SPNEGO_REQ_FLAG; asn1_end_tag(asn1); break; /* Read mechToken */ case ASN1_CONTEXT(2): asn1_start_tag(asn1, ASN1_CONTEXT(2)); asn1_read_OctetString(asn1, mem_ctx, &token->mechToken); asn1_end_tag(asn1); break; /* Read mecListMIC */ case ASN1_CONTEXT(3): { uint8_t type_peek; asn1_start_tag(asn1, ASN1_CONTEXT(3)); if (!asn1_peek_uint8(asn1, &type_peek)) { asn1->has_error = true; break; } if (type_peek == ASN1_OCTET_STRING) { asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC); } else { /* RFC 2478 says we have an Octet String here, but W2k sends something different... */ char *mechListMIC; asn1_push_tag(asn1, ASN1_SEQUENCE(0)); asn1_push_tag(asn1, ASN1_CONTEXT(0)); asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC); asn1_pop_tag(asn1); asn1_pop_tag(asn1); token->targetPrincipal = mechListMIC; } asn1_end_tag(asn1); break; } default: asn1->has_error = true; break; } } asn1_end_tag(asn1); asn1_end_tag(asn1); return !asn1->has_error; }
/* * Get a new empty handle to fill in with your own info */ SMBCCTX * smbc_new_context(void) { SMBCCTX *context; /* The first call to this function should initialize the module */ SMB_THREAD_ONCE(&SMBC_initialized, SMBC_module_init, NULL); /* * All newly added context fields should be placed in * SMBC_internal_data, not directly in SMBCCTX. */ context = SMB_MALLOC_P(SMBCCTX); if (!context) { errno = ENOMEM; return NULL; } ZERO_STRUCTP(context); context->internal = SMB_MALLOC_P(struct SMBC_internal_data); if (!context->internal) { SAFE_FREE(context); errno = ENOMEM; return NULL; } /* Initialize the context and establish reasonable defaults */ ZERO_STRUCTP(context->internal); smbc_setDebug(context, 0); smbc_setTimeout(context, 20000); smbc_setOptionFullTimeNames(context, False); smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE); smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE); smbc_setOptionCaseSensitive(context, False); smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */ smbc_setOptionUrlEncodeReaddirEntries(context, False); smbc_setOptionOneSharePerServer(context, False); smbc_setFunctionAuthData(context, SMBC_get_auth_data); smbc_setFunctionCheckServer(context, SMBC_check_server); smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server); smbc_setOptionUserData(context, NULL); smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server); smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server); smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server); smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers); smbc_setFunctionOpen(context, SMBC_open_ctx); smbc_setFunctionCreat(context, SMBC_creat_ctx); smbc_setFunctionRead(context, SMBC_read_ctx); smbc_setFunctionWrite(context, SMBC_write_ctx); smbc_setFunctionClose(context, SMBC_close_ctx); smbc_setFunctionUnlink(context, SMBC_unlink_ctx); smbc_setFunctionRename(context, SMBC_rename_ctx); smbc_setFunctionLseek(context, SMBC_lseek_ctx); smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx); smbc_setFunctionStat(context, SMBC_stat_ctx); smbc_setFunctionStatVFS(context, SMBC_statvfs_ctx); smbc_setFunctionFstatVFS(context, SMBC_fstatvfs_ctx); smbc_setFunctionFstat(context, SMBC_fstat_ctx); smbc_setFunctionOpendir(context, SMBC_opendir_ctx); smbc_setFunctionClosedir(context, SMBC_closedir_ctx); smbc_setFunctionReaddir(context, SMBC_readdir_ctx); smbc_setFunctionGetdents(context, SMBC_getdents_ctx); smbc_setFunctionMkdir(context, SMBC_mkdir_ctx); smbc_setFunctionRmdir(context, SMBC_rmdir_ctx); smbc_setFunctionTelldir(context, SMBC_telldir_ctx); smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx); smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx); smbc_setFunctionChmod(context, SMBC_chmod_ctx); smbc_setFunctionUtimes(context, SMBC_utimes_ctx); smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx); smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx); smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx); smbc_setFunctionListxattr(context, SMBC_listxattr_ctx); smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx); smbc_setFunctionPrintFile(context, SMBC_print_file_ctx); smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx); smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx); return context; }
/* * This is a poll(2)-emulation using select for systems not providing a native * poll implementation. * * Keep in mind that select is terribly inefficient. The interface is simply not * meant to be used with maximum descriptor value greater, say, 32 or so. With * a value as high as 1024 on Linux you'll pay dearly in every single call. * poll() will be orders of magnitude faster. */ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) { fd_set readfds, writefds, exceptfds; struct timeval tv, *ptv; socket_t max_fd; int rc; nfds_t i; if (fds == NULL) { errno = EFAULT; return -1; } FD_ZERO (&readfds); FD_ZERO (&writefds); FD_ZERO (&exceptfds); /* compute fd_sets and find largest descriptor */ for (rc = -1, max_fd = 0, i = 0; i < nfds; i++) { if (fds[i].fd == SSH_INVALID_SOCKET) { continue; } #ifndef _WIN32 if (fds[i].fd >= FD_SETSIZE) { rc = -1; break; } #endif if (fds[i].events & (POLLIN | POLLRDNORM)) { FD_SET (fds[i].fd, &readfds); } if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { FD_SET (fds[i].fd, &writefds); } if (fds[i].events & (POLLPRI | POLLRDBAND)) { FD_SET (fds[i].fd, &exceptfds); } if (fds[i].fd > max_fd && (fds[i].events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM | POLLRDBAND | POLLWRNORM | POLLWRBAND))) { max_fd = fds[i].fd; rc = 0; } } if (max_fd == SSH_INVALID_SOCKET || rc == -1) { errno = EINVAL; return -1; } if (timeout < 0) { ptv = NULL; } else { ptv = &tv; if (timeout == 0) { tv.tv_sec = 0; tv.tv_usec = 0; } else { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } } rc = select (max_fd + 1, &readfds, &writefds, &exceptfds, ptv); if (rc < 0) { return -1; } for (rc = 0, i = 0; i < nfds; i++) if (fds[i].fd >= 0) { fds[i].revents = 0; if (FD_ISSET(fds[i].fd, &readfds)) { int save_errno = errno; char data[64] = {0}; int ret; /* support for POLLHUP */ ret = recv(fds[i].fd, data, 64, MSG_PEEK); #ifdef _WIN32 if ((ret == -1) && (errno == WSAESHUTDOWN || errno == WSAECONNRESET || errno == WSAECONNABORTED || errno == WSAENETRESET)) { #else if ((ret == -1) && (errno == ESHUTDOWN || errno == ECONNRESET || errno == ECONNABORTED || errno == ENETRESET)) { #endif fds[i].revents |= POLLHUP; } else { fds[i].revents |= fds[i].events & (POLLIN | POLLRDNORM); } errno = save_errno; } if (FD_ISSET(fds[i].fd, &writefds)) { fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND); } if (FD_ISSET(fds[i].fd, &exceptfds)) { fds[i].revents |= fds[i].events & (POLLPRI | POLLRDBAND); } if (fds[i].revents & ~POLLHUP) { rc++; } } else { fds[i].revents = POLLNVAL; } return rc; } void ssh_poll_init(void) { ssh_poll_emu = bsd_poll; } void ssh_poll_cleanup(void) { ssh_poll_emu = bsd_poll; } int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) { return (ssh_poll_emu)(fds, nfds, timeout); } #endif /* HAVE_POLL */ /** * @brief Allocate a new poll object, which could be used within a poll context. * * @param fd Socket that will be polled. * @param events Poll events that will be monitored for the socket. i.e. * POLLIN, POLLPRI, POLLOUT * @param cb Function to be called if any of the events are set. * The prototype of cb is: * int (*ssh_poll_callback)(ssh_poll_handle p, socket_t fd, * int revents, void *userdata); * @param userdata Userdata to be passed to the callback function. NULL if * not needed. * * @return A new poll object, NULL on error */ ssh_poll_handle ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb, void *userdata) { ssh_poll_handle p; p = malloc(sizeof(struct ssh_poll_handle_struct)); if (p == NULL) { return NULL; } ZERO_STRUCTP(p); p->x.fd = fd; p->events = events; p->cb = cb; p->cb_data = userdata; return p; }
/* fill in the cldap netlogon union for a given version */ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *domain, const char *netbios_domain, struct dom_sid *domain_sid, const char *domain_guid, const char *user, uint32_t acct_control, const char *src_address, uint32_t version, struct loadparm_context *lp_ctx, struct netlogon_samlogon_response *netlogon, bool fill_on_blank_request) { const char *dom_attrs[] = {"objectGUID", NULL}; const char *none_attrs[] = {NULL}; struct ldb_result *dom_res = NULL, *user_res = NULL; int ret; const char **services = lpcfg_server_services(lp_ctx); uint32_t server_type; const char *pdc_name; struct GUID domain_uuid; const char *dns_domain; const char *forest_domain; const char *pdc_dns_name; const char *flatname; const char *server_site; const char *client_site; const char *pdc_ip; struct ldb_dn *domain_dn = NULL; struct interface *ifaces; bool user_known, am_rodc; NTSTATUS status; /* the domain parameter could have an optional trailing "." */ if (domain && domain[strlen(domain)-1] == '.') { domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); NT_STATUS_HAVE_NO_MEMORY(domain); } /* Lookup using long or short domainname */ if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) { domain_dn = ldb_get_default_basedn(sam_ctx); } if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) { domain_dn = ldb_get_default_basedn(sam_ctx); } if (domain_dn) { const char *domain_identifier = domain != NULL ? domain : netbios_domain; ret = ldb_search(sam_ctx, mem_ctx, &dom_res, domain_dn, LDB_SCOPE_BASE, dom_attrs, "objectClass=domain"); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain_identifier, ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } if (dom_res->count != 1) { DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain_identifier, ldb_dn_get_linearized(domain_dn))); return NT_STATUS_NO_SUCH_DOMAIN; } } /* Lookup using GUID or SID */ if ((dom_res == NULL) && (domain_guid || domain_sid)) { if (domain_guid) { struct GUID binary_guid; struct ldb_val guid_val; /* By this means, we ensure we don't have funny stuff in the GUID */ status = GUID_from_string(domain_guid, &binary_guid); if (!NT_STATUS_IS_OK(status)) { return status; } /* And this gets the result into the binary format we want anyway */ status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val); if (!NT_STATUS_IS_OK(status)) { return status; } ret = ldb_search(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, "(&(objectCategory=DomainDNS)(objectGUID=%s))", ldb_binary_encode(mem_ctx, guid_val)); } else { /* domain_sid case */ ret = ldb_search(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, "(&(objectCategory=DomainDNS)(objectSid=%s))", dom_sid_string(mem_ctx, domain_sid)); } if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n", domain_guid, dom_sid_string(mem_ctx, domain_sid), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } else if (dom_res->count == 1) { /* Ok, now just check it is our domain */ if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx), dom_res->msgs[0]->dn) != 0) { DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n", domain_guid, dom_sid_string(mem_ctx, domain_sid))); return NT_STATUS_NO_SUCH_DOMAIN; } } else { DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n", domain_guid, dom_sid_string(mem_ctx, domain_sid))); return NT_STATUS_NO_SUCH_DOMAIN; } } if (dom_res == NULL && fill_on_blank_request) { /* blank inputs gives our domain - tested against w2k8r2. Without this ADUC on Win7 won't start */ domain_dn = ldb_get_default_basedn(sam_ctx); ret = ldb_search(sam_ctx, mem_ctx, &dom_res, domain_dn, LDB_SCOPE_BASE, dom_attrs, "objectClass=domain"); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", lpcfg_dnsdomain(lp_ctx), ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } } if (dom_res == NULL) { DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n")); return NT_STATUS_NO_SUCH_DOMAIN; } /* work around different inputs for not-specified users */ if (!user) { user = ""; } /* Enquire about any valid username with just a CLDAP packet - * if kerberos didn't also do this, the security folks would * scream... */ if (user[0]) { \ /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */ if (acct_control == (uint32_t)-1) { acct_control = 0; } acct_control = acct_control & (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */ ret = ldb_search(sam_ctx, mem_ctx, &user_res, dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, none_attrs, "(&(objectClass=user)(samAccountName=%s)" "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", ldb_binary_encode_string(mem_ctx, user), UF_ACCOUNTDISABLE, ds_acb2uf(acct_control)); if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n", user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_USER; } else if (user_res->count == 1) { user_known = true; } else { user_known = false; } } else { user_known = true; } server_type = DS_SERVER_DS | DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV; if (samdb_is_pdc(sam_ctx)) { server_type |= DS_SERVER_PDC; } if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) { server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6; } if (samdb_is_gc(sam_ctx)) { server_type |= DS_SERVER_GC; } if (str_list_check(services, "ldap")) { server_type |= DS_SERVER_LDAP; } if (str_list_check(services, "kdc")) { server_type |= DS_SERVER_KDC; } if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) { server_type |= DS_SERVER_WRITABLE; } pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lpcfg_netbios_name(lp_ctx)); NT_STATUS_HAVE_NO_MEMORY(pdc_name); domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); dns_domain = lpcfg_dnsdomain(lp_ctx); forest_domain = samdb_forest_name(sam_ctx, mem_ctx); NT_STATUS_HAVE_NO_MEMORY(forest_domain); pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", strlower_talloc(mem_ctx, lpcfg_netbios_name(lp_ctx)), dns_domain); NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name); flatname = lpcfg_workgroup(lp_ctx); server_site = samdb_server_site_name(sam_ctx, mem_ctx); NT_STATUS_HAVE_NO_MEMORY(server_site); client_site = samdb_client_site_name(sam_ctx, mem_ctx, src_address, NULL); NT_STATUS_HAVE_NO_MEMORY(client_site); if (strcasecmp(server_site, client_site) == 0) { server_type |= DS_SERVER_CLOSEST; } load_interface_list(mem_ctx, lp_ctx, &ifaces); if (src_address) { pdc_ip = iface_list_best_ip(ifaces, src_address); } else { pdc_ip = iface_list_first_v4(ifaces); } if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) { /* this matches windows behaviour */ pdc_ip = "127.0.0.1"; } ZERO_STRUCTP(netlogon); /* check if either of these bits is present */ if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { uint32_t extra_flags = 0; netlogon->ntver = NETLOGON_NT_VERSION_5EX; /* could check if the user exists */ if (user_known) { netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX; } else { netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX; } netlogon->data.nt5_ex.pdc_name = pdc_name; netlogon->data.nt5_ex.user_name = user; netlogon->data.nt5_ex.domain_name = flatname; netlogon->data.nt5_ex.domain_uuid = domain_uuid; netlogon->data.nt5_ex.forest = forest_domain; netlogon->data.nt5_ex.dns_domain = dns_domain; netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name; netlogon->data.nt5_ex.server_site = server_site; netlogon->data.nt5_ex.client_site = client_site; if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) { /* note that this is always a IPV4 address */ extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP; netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2; netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip; netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8); } netlogon->data.nt5_ex.server_type = server_type; netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags; netlogon->data.nt5_ex.lmnt_token = 0xFFFF; netlogon->data.nt5_ex.lm20_token = 0xFFFF; } else if (version & NETLOGON_NT_VERSION_5) { netlogon->ntver = NETLOGON_NT_VERSION_5; /* could check if the user exists */ if (user_known) { netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE; } else { netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN; } netlogon->data.nt5.pdc_name = pdc_name; netlogon->data.nt5.user_name = user; netlogon->data.nt5.domain_name = flatname; netlogon->data.nt5.domain_uuid = domain_uuid; netlogon->data.nt5.forest = forest_domain; netlogon->data.nt5.dns_domain = dns_domain; netlogon->data.nt5.pdc_dns_name = pdc_dns_name; netlogon->data.nt5.pdc_ip = pdc_ip; netlogon->data.nt5.server_type = server_type; netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5; netlogon->data.nt5.lmnt_token = 0xFFFF; netlogon->data.nt5.lm20_token = 0xFFFF; } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ { netlogon->ntver = NETLOGON_NT_VERSION_1; /* could check if the user exists */ if (user_known) { netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE; } else { netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN; } netlogon->data.nt4.pdc_name = pdc_name; netlogon->data.nt4.user_name = user; netlogon->data.nt4.domain_name = flatname; netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1; netlogon->data.nt4.lmnt_token = 0xFFFF; netlogon->data.nt4.lm20_token = 0xFFFF; } return NT_STATUS_OK; }
static SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, uint16_t port, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c = NULL; const char *server_n = server; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32_t fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; int flags = 0; struct smbXcli_tcon *tcon = NULL; int signing_state = SMB_SIGNING_DEFAULT; ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && share != NULL && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (!cli_state_has_tcon(srv->cli)) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, smbXcli_conn_remote_name(srv->cli->conn), srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tree_connect(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); status = NT_STATUS_OK; } else { status = cli_get_fs_attr_info(c, &fs_attrs); } if (!NT_STATUS_IS_OK(status)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", nt_errstr(status))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else if (!is_ipc) { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { const char *remote_name = smbXcli_conn_remote_name(srv->cli->conn); srv->dev = (dev_t)(str_checksum(remote_name) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); status = NT_STATUS_UNSUCCESSFUL; if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (smbc_getOptionFallbackAfterKerberos(context)) { flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; } if (smbc_getOptionUseCCache(context)) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } if (smbc_getOptionUseNTHash(context)) { flags |= CLI_FULL_CONNECTION_USE_NT_HASH; } if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) { signing_state = SMB_SIGNING_REQUIRED; } if (port == 0) { if (share == NULL || *share == '\0' || is_ipc) { /* * Try 139 first for IPC$ */ status = cli_connect_nb(server_n, NULL, NBT_SMB_PORT, 0x20, smbc_getNetbiosName(context), signing_state, flags, &c); } } if (!NT_STATUS_IS_OK(status)) { /* * No IPC$ or 139 did not work */ status = cli_connect_nb(server_n, NULL, port, 0x20, smbc_getNetbiosName(context), signing_state, flags, &c); } if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); return NULL; } cli_set_timeout(c, smbc_getTimeout(context)); status = smbXcli_negprot(c->conn, c->timeout, lp_client_min_protocol(), lp_client_max_protocol()); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { /* Ensure we ask for some initial credits. */ smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS); } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if (smbXcli_conn_dfs_supported(c->conn) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, port, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tree_connect(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { tcon = c->smb2.tcon; } else { tcon = c->smb1.tcon; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); status = NT_STATUS_OK; } else { status = cli_get_fs_attr_info(c, &fs_attrs); } if (!NT_STATUS_IS_OK(status)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", nt_errstr(status))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else if (!is_ipc) { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); smbXcli_tcon_set_fs_attributes(tcon, fs_attrs); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); DLIST_ADD(srv->cli, c); srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_pathinfo3 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { if (c != NULL) { cli_shutdown(c); } SAFE_FREE(srv); return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
static SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c; struct nmb_name called, calling; const char *server_n = server; struct sockaddr_storage ss; int tried_reverse = 0; int port_try_first; int port_try_next; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32 fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; zero_sockaddr(&ss); ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, srv->cli->desthost, srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tcon_andx(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: zero_sockaddr(&ss); /* have to open a new connection */ if ((c = cli_initialise()) == NULL) { errno = ENOMEM; return NULL; } if (smbc_getOptionUseKerberos(context)) { c->use_kerberos = True; } if (smbc_getOptionFallbackAfterKerberos(context)) { c->fallback_after_kerberos = True; } if (smbc_getOptionUseCCache(context)) { c->use_ccache = True; } c->timeout = smbc_getTimeout(context); /* * Force use of port 139 for first try if share is $IPC, empty, or * null, so browse lists can work */ if (share == NULL || *share == '\0' || is_ipc) { port_try_first = 139; port_try_next = 445; } else { port_try_first = 445; port_try_next = 139; } c->port = port_try_first; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { /* First connection attempt failed. Try alternate port. */ c->port = port_try_next; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } } if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } else { /* Try one more time, but ensure we don't loop */ /* Only try this if server is an IP address ... */ if (is_ipaddress(server) && !tried_reverse) { fstring remote_name; struct sockaddr_storage rem_ss; if (!interpret_string_addr(&rem_ss, server, NI_NUMERICHOST)) { DEBUG(4, ("Could not convert IP address " "%s to struct sockaddr_storage\n", server)); errno = ETIMEDOUT; return NULL; } tried_reverse++; /* Yuck */ if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { make_nmb_name(&called, remote_name, 0x20); goto again; } } } errno = ETIMEDOUT; return NULL; } DEBUG(4,(" session request ok\n")); status = cli_negprot(c); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_session_setup fail with username=[%s], password=[%s]\n", username_used, *pp_password); /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } status = cli_init_creds(c, username_used, *pp_workgroup, *pp_password); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if ((c->capabilities & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tcon_andx(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_tcon_andx return %08X, errno=[%d]\n", NT_STATUS_V(status), errno); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive(c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
void aldb_init_als(LOCAL_GRP *als) { if (als == NULL) return; ZERO_STRUCTP(als); }
void zero_sockaddr(struct sockaddr_storage *pss) { ZERO_STRUCTP(pss); /* Ensure we're at least a valid sockaddr-storage. */ pss->ss_family = AF_INET; }