NTSTATUS make_session_info_system(TALLOC_CTX *mem_ctx, struct auth_session_info **session_info) { if (system_info == NULL) return NT_STATUS_UNSUCCESSFUL; *session_info = copy_session_info(mem_ctx, system_info); return (*session_info != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; }
struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax, const struct tsocket_address *remote_address, const struct auth_session_info *session_info, struct messaging_context *msg_ctx) { struct pipes_struct *p; struct pipe_rpc_fns *context_fns; const char *pipe_name; int ret; pipe_name = get_pipe_name_from_syntax(talloc_tos(), syntax); DEBUG(4,("Create pipe requested %s\n", pipe_name)); ret = make_base_pipes_struct(mem_ctx, msg_ctx, pipe_name, NCALRPC, RPC_LITTLE_ENDIAN, false, remote_address, NULL, &p); if (ret) { DEBUG(0,("ERROR! no memory for pipes_struct!\n")); return NULL; } if (!init_pipe_handles(p, syntax)) { DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n")); TALLOC_FREE(p); return NULL; } p->session_info = copy_session_info(p, session_info); if (p->session_info == NULL) { DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n")); close_policy_by_pipe(p); TALLOC_FREE(p); return NULL; } context_fns = talloc(p, struct pipe_rpc_fns); if (context_fns == NULL) { DEBUG(0,("talloc() failed!\n")); TALLOC_FREE(p); return NULL; } context_fns->next = context_fns->prev = NULL; context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(syntax); context_fns->cmds = rpc_srv_get_pipe_cmds(syntax); context_fns->context_id = 0; context_fns->syntax = *syntax; /* add to the list of open contexts */ DLIST_ADD(p->contexts, context_fns); DEBUG(4,("Created internal pipe %s\n", pipe_name)); return p; }
static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn, TALLOC_CTX *mem_ctx, int snum, struct auth_session_info *session_info, struct auth_session_info **presult) { struct auth_session_info *result; if (lp_guest_only(snum)) { return make_session_info_guest(mem_ctx, presult); } /* * This is the normal security != share case where we have a * valid vuid from the session setup. */ if (security_session_user_level(session_info, NULL) < SECURITY_USER) { if (!lp_guest_ok(snum)) { DEBUG(2, ("guest user (from session setup) " "not permitted to access this share " "(%s)\n", lp_servicename(talloc_tos(), snum))); return NT_STATUS_ACCESS_DENIED; } } else { if (!user_ok_token(session_info->unix_info->unix_name, session_info->info->domain_name, session_info->security_token, snum)) { DEBUG(2, ("user '%s' (from session setup) not " "permitted to access this share " "(%s)\n", session_info->unix_info->unix_name, lp_servicename(talloc_tos(), snum))); return NT_STATUS_ACCESS_DENIED; } } result = copy_session_info(mem_ctx, session_info); if (result == NULL) { return NT_STATUS_NO_MEMORY; } *presult = result; return NT_STATUS_OK; }
NTSTATUS make_internal_rpc_pipe_socketpair( TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const char *pipe_name, const struct ndr_syntax_id *syntax, const struct tsocket_address *remote_address, const struct tsocket_address *local_address, const struct auth_session_info *session_info, struct npa_state **pnpa) { TALLOC_CTX *tmp_ctx = talloc_stackframe(); struct named_pipe_client *npc; struct tevent_req *subreq; struct npa_state *npa; NTSTATUS status; int error; int rc; DEBUG(4, ("Create of internal pipe %s requested\n", pipe_name)); npa = npa_state_init(tmp_ctx); if (npa == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } npa->file_type = FILE_TYPE_MESSAGE_MODE_PIPE; npa->device_state = 0xff | 0x0400 | 0x0100; npa->allocation_size = 4096; npc = named_pipe_client_init(npa, ev_ctx, msg_ctx, pipe_name, NULL, /* term_fn */ npa->file_type, npa->device_state, npa->allocation_size, NULL); /* private_data */ if (npc == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } npa->private_data = (void*) npc; rc = tstream_npa_socketpair(npa->file_type, npa, &npa->stream, npc, &npc->tstream); if (rc == -1) { status = map_nt_error_from_unix(errno); goto out; } npc->remote_client_addr = tsocket_address_copy(remote_address, npc); if (npc->remote_client_addr == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } npc->remote_client_name = tsocket_address_inet_addr_string(npc->remote_client_addr, npc); if (npc->remote_client_name == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } npc->local_server_addr = tsocket_address_copy(local_address, npc); if (npc->local_server_addr == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } npc->local_server_name = tsocket_address_inet_addr_string( npc->local_server_addr, npc); if (npc->local_server_name == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } npc->session_info = copy_session_info(npc, session_info); if (npc->session_info == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } rc = make_server_pipes_struct(npc, npc->msg_ctx, npc->pipe_name, NCACN_NP, npc->remote_client_addr, npc->local_server_addr, npc->session_info, &npc->p, &error); if (rc == -1) { status = map_nt_error_from_unix(error); goto out; } npc->write_queue = tevent_queue_create(npc, "npa_server_write_queue"); if (npc->write_queue == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } subreq = dcerpc_read_ncacn_packet_send(npc, npc->ev, npc->tstream); if (subreq == NULL) { DEBUG(2, ("Failed to start receiving packets\n")); status = NT_STATUS_PIPE_BROKEN; goto out; } tevent_req_set_callback(subreq, named_pipe_packet_process, npc); *pnpa = talloc_steal(mem_ctx, npa); status = NT_STATUS_OK; out: talloc_free(tmp_ctx); return status; }
struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax, const struct tsocket_address *remote_address, const struct tsocket_address *local_address, const struct auth_session_info *session_info, struct messaging_context *msg_ctx) { struct pipes_struct *p; struct pipe_rpc_fns *context_fns; const char *pipe_name; int ret; const struct ndr_interface_table *table; table = ndr_table_by_uuid(&syntax->uuid); if (table == NULL) { DEBUG(0,("unknown interface\n")); return NULL; } pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table); DEBUG(4,("Create pipe requested %s\n", pipe_name)); ret = make_base_pipes_struct(mem_ctx, msg_ctx, pipe_name, NCALRPC, RPC_LITTLE_ENDIAN, remote_address, local_address, &p); if (ret) { DEBUG(0,("ERROR! no memory for pipes_struct!\n")); return NULL; } if (!init_pipe_handles(p, syntax)) { DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n")); TALLOC_FREE(p); return NULL; } p->session_info = copy_session_info(p, session_info); if (p->session_info == NULL) { DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n")); close_policy_by_pipe(p); TALLOC_FREE(p); return NULL; } context_fns = talloc_zero(p, struct pipe_rpc_fns); if (context_fns == NULL) { DEBUG(0,("talloc() failed!\n")); TALLOC_FREE(p); return NULL; } context_fns->next = context_fns->prev = NULL; context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(syntax); context_fns->cmds = rpc_srv_get_pipe_cmds(syntax); context_fns->context_id = 0; context_fns->syntax = *syntax; /* add to the list of open contexts */ DLIST_ADD(p->contexts, context_fns); DEBUG(4,("Created internal pipe %s\n", pipe_name)); return p; }
static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx, struct tevent_context *ev, struct messaging_context *msg, connection_struct **pconn, int snum, const char *path, const struct auth_session_info *session_info) { connection_struct *conn; char *connpath; const char *vfs_user; struct smbd_server_connection *sconn; const char *servicename = lp_const_servicename(snum); sconn = talloc_zero(ctx, struct smbd_server_connection); if (sconn == NULL) { return NT_STATUS_NO_MEMORY; } sconn->ev_ctx = ev; sconn->msg_ctx = msg; sconn->sock = -1; sconn->smb1.echo_handler.trusted_fd = -1; sconn->smb1.echo_handler.socket_lock_fd = -1; conn = conn_new(sconn); if (conn == NULL) { TALLOC_FREE(sconn); return NT_STATUS_NO_MEMORY; } /* Now we have conn, we need to make sconn a child of conn, * for a proper talloc tree */ talloc_steal(conn, sconn); if (snum == -1 && servicename == NULL) { servicename = "Unknown Service (snum == -1)"; } connpath = talloc_strdup(conn, path); if (!connpath) { TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } connpath = talloc_string_sub(conn, connpath, "%S", servicename); if (!connpath) { TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } /* needed for smbd_vfs_init() */ conn->params->service = snum; conn->cnum = TID_FIELD_INVALID; if (session_info != NULL) { conn->session_info = copy_session_info(conn, session_info); if (conn->session_info == NULL) { DEBUG(0, ("copy_serverinfo failed\n")); TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } vfs_user = conn->session_info->unix_info->unix_name; } else { /* use current authenticated user in absence of session_info */ vfs_user = get_current_username(); } set_conn_connectpath(conn, connpath); /* * New code to check if there's a share security descripter * added from NT server manager. This is done after the * smb.conf checks are done as we need a uid and token. JRA. * */ if (conn->session_info) { share_access_check(conn->session_info->security_token, servicename, MAXIMUM_ALLOWED_ACCESS, &conn->share_access); if ((conn->share_access & FILE_WRITE_DATA) == 0) { if ((conn->share_access & FILE_READ_DATA) == 0) { /* No access, read or write. */ DEBUG(0,("create_conn_struct: connection to %s " "denied due to security " "descriptor.\n", servicename)); conn_free(conn); return NT_STATUS_ACCESS_DENIED; } else { conn->read_only = true; } } } else { conn->share_access = 0; conn->read_only = true; } if (!smbd_vfs_init(conn)) { NTSTATUS status = map_nt_error_from_unix(errno); DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n")); conn_free(conn); return status; } /* this must be the first filesystem operation that we do */ if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) { DEBUG(0,("VFS connect failed!\n")); conn_free(conn); return NT_STATUS_UNSUCCESSFUL; } conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); *pconn = conn; return NT_STATUS_OK; }
static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn, TALLOC_CTX *mem_ctx, int snum, struct auth_session_info *vuid_serverinfo, DATA_BLOB password, struct auth_session_info **presult) { if (lp_guest_only(snum)) { return make_session_info_guest(mem_ctx, presult); } if (vuid_serverinfo != NULL) { struct auth_session_info *result; /* * This is the normal security != share case where we have a * valid vuid from the session setup. */ if (security_session_user_level(vuid_serverinfo, NULL) < SECURITY_USER) { if (!lp_guest_ok(snum)) { DEBUG(2, ("guest user (from session setup) " "not permitted to access this share " "(%s)\n", lp_servicename(snum))); return NT_STATUS_ACCESS_DENIED; } } else { if (!user_ok_token(vuid_serverinfo->unix_info->unix_name, vuid_serverinfo->info->domain_name, vuid_serverinfo->security_token, snum)) { DEBUG(2, ("user '%s' (from session setup) not " "permitted to access this share " "(%s)\n", vuid_serverinfo->unix_info->unix_name, lp_servicename(snum))); return NT_STATUS_ACCESS_DENIED; } } result = copy_session_info(mem_ctx, vuid_serverinfo); if (result == NULL) { return NT_STATUS_NO_MEMORY; } *presult = result; return NT_STATUS_OK; } if (lp_security() == SEC_SHARE) { fstring user; bool guest; /* add the sharename as a possible user name if we are in share mode security */ add_session_user(sconn, lp_servicename(snum)); /* shall we let them in? */ if (!authorise_login(sconn, snum,user,password,&guest)) { DEBUG( 2, ( "Invalid username/password for [%s]\n", lp_servicename(snum)) ); return NT_STATUS_WRONG_PASSWORD; } return make_session_info_from_username(mem_ctx, user, guest, presult); } DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); return NT_STATUS_ACCESS_DENIED; }
NTSTATUS make_session_info_guest(TALLOC_CTX *mem_ctx, struct auth_session_info **session_info) { *session_info = copy_session_info(mem_ctx, guest_info); return (*session_info != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; }
static bool check_user_ok(connection_struct *conn, uint64_t vuid, const struct auth_session_info *session_info, int snum) { unsigned int i; bool readonly_share = false; bool admin_user = false; struct vuid_cache_entry *ent = NULL; uint32_t share_access = 0; NTSTATUS status; for (i=0; i<VUID_CACHE_SIZE; i++) { ent = &conn->vuid_cache->array[i]; if (ent->vuid == vuid) { if (vuid == UID_FIELD_INVALID) { /* * Slow path, we don't care * about the array traversal. */ continue; } free_conn_session_info_if_unused(conn); conn->session_info = ent->session_info; conn->read_only = ent->read_only; conn->share_access = ent->share_access; return(True); } } status = check_user_share_access(conn, session_info, &share_access, &readonly_share); if (!NT_STATUS_IS_OK(status)) { return false; } admin_user = token_contains_name_in_list( session_info->unix_info->unix_name, session_info->info->domain_name, NULL, session_info->security_token, lp_admin_users(snum)); ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry]; conn->vuid_cache->next_entry = (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE; TALLOC_FREE(ent->session_info); /* * If force_user was set, all session_info's are based on the same * username-based faked one. */ ent->session_info = copy_session_info( conn, conn->force_user ? conn->session_info : session_info); if (ent->session_info == NULL) { ent->vuid = UID_FIELD_INVALID; return false; } /* * It's actually OK to call check_user_ok() with * vuid == UID_FIELD_INVALID as called from change_to_user_by_session(). * All this will do is throw away one entry in the cache. */ ent->vuid = vuid; ent->read_only = readonly_share; ent->share_access = share_access; free_conn_session_info_if_unused(conn); conn->session_info = ent->session_info; if (vuid == UID_FIELD_INVALID) { /* * Not strictly needed, just make it really * clear this entry is actually an unused one. */ ent->read_only = false; ent->share_access = 0; ent->session_info = NULL; } conn->read_only = readonly_share; conn->share_access = share_access; if (admin_user) { DEBUG(2,("check_user_ok: user %s is an admin user. " "Setting uid as %d\n", conn->session_info->unix_info->unix_name, sec_initial_uid() )); conn->session_info->unix_token->uid = sec_initial_uid(); } return(True); }