static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct messaging_context *msg_ctx, struct auth_session_info *session_info, int snum, struct connection_struct **conn_out) { struct connection_struct *conn = NULL; NTSTATUS status; status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn, snum, lp_path(mem_ctx, snum), session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("failed to create conn for vfs: %s\n", nt_errstr(status))); return status; } status = set_conn_force_user_group(conn, snum); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("failed set force user / group\n")); goto err_free_conn; } *conn_out = conn; return NT_STATUS_OK; err_free_conn: SMB_VFS_DISCONNECT(conn); conn_free(conn); return status; }
uint32_t _fss_IsPathSupported(struct pipes_struct *p, struct fss_IsPathSupported *r) { int snum; char *service; char *base_vol; NTSTATUS status; struct connection_struct *conn; char *share; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } if (!fss_permitted(p)) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return fss_ntstatus_map(status); } snum = find_service(tmp_ctx, share, &service); if ((snum == -1) || (service == NULL)) { DEBUG(0, ("share at %s not found\n", r->in.ShareName)); talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } status = fss_vfs_conn_create(tmp_ctx, server_event_context(), p->msg_ctx, p->session_info, snum, &conn); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } if (!become_user_by_session(conn, p->session_info)) { DEBUG(0, ("failed to become user\n")); talloc_free(tmp_ctx); fss_vfs_conn_destroy(conn); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, lp_path(tmp_ctx, snum), &base_vol); unbecome_user(); fss_vfs_conn_destroy(conn); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return FSRVP_E_NOT_SUPPORTED; } *r->out.OwnerMachineName = lp_netbios_name(); *r->out.SupportedByThisProvider = 1; talloc_free(tmp_ctx); return 0; }
static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn, connection_struct *conn, int snum, struct user_struct *vuser, const char *pdev) { struct smbd_server_connection *sconn = xconn->client->sconn; struct smb_filename *smb_fname_cpath = NULL; fstring dev; int ret; bool on_err_call_dis_hook = false; uid_t effuid; gid_t effgid; NTSTATUS status; fstrcpy(dev, pdev); status = share_sanity_checks(sconn->remote_address, sconn->remote_hostname, snum, dev); if (NT_STATUS_IS_ERR(status)) { goto err_root_exit; } conn->params->service = snum; status = create_connection_session_info(sconn, conn, snum, vuser->session_info, &conn->session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("create_connection_session_info failed: %s\n", nt_errstr(status))); goto err_root_exit; } if (lp_guest_only(snum)) { conn->force_user = true; } conn->num_files_open = 0; conn->lastused = conn->lastused_count = time(NULL); conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) ); /* Case options for the share. */ if (lp_case_sensitive(snum) == Auto) { /* We will be setting this per packet. Set to be case * insensitive for now. */ conn->case_sensitive = False; } else { conn->case_sensitive = (bool)lp_case_sensitive(snum); } conn->case_preserve = lp_preserve_case(snum); conn->short_case_preserve = lp_short_preserve_case(snum); conn->encrypt_level = lp_smb_encrypt(snum); conn->veto_list = NULL; conn->hide_list = NULL; conn->veto_oplock_list = NULL; conn->aio_write_behind_list = NULL; conn->read_only = lp_read_only(SNUM(conn)); status = set_conn_force_user_group(conn, snum); if (!NT_STATUS_IS_OK(status)) { goto err_root_exit; } conn->vuid = vuser->vuid; { char *s = talloc_sub_advanced(talloc_tos(), lp_servicename(talloc_tos(), SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, lp_path(talloc_tos(), snum)); if (!s) { status = NT_STATUS_NO_MEMORY; goto err_root_exit; } if (!set_conn_connectpath(conn,s)) { TALLOC_FREE(s); status = NT_STATUS_NO_MEMORY; goto err_root_exit; } DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(talloc_tos(), snum))); TALLOC_FREE(s); } /* * Set up the share security descriptor. * NOTE - we use the *INCOMING USER* session_info * here, as does (indirectly) change_to_user(), * which can be called on any incoming packet. * This way we set up the share access based * on the authenticated user, not the forced * user. See bug: * * https://bugzilla.samba.org/show_bug.cgi?id=9878 */ status = check_user_share_access(conn, vuser->session_info, &conn->share_access, &conn->read_only); if (!NT_STATUS_IS_OK(status)) { goto err_root_exit; } /* Initialise VFS function pointers */ if (!smbd_vfs_init(conn)) { DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(talloc_tos(), snum))); status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } /* ROOT Activities: */ /* explicitly check widelinks here so that we can correctly warn * in the logs. */ widelinks_warning(snum); /* * Enforce the max connections parameter. */ if ((lp_max_connections(snum) > 0) && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >= lp_max_connections(snum))) { DEBUG(1, ("Max connections (%d) exceeded for %s\n", lp_max_connections(snum), lp_servicename(talloc_tos(), snum))); status = NT_STATUS_INSUFFICIENT_RESOURCES; goto err_root_exit; } /* Invoke VFS make connection hook - this must be the first filesystem operation that we do. */ if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum), conn->session_info->unix_info->unix_name) < 0) { DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n", lp_servicename(talloc_tos(), snum), conn->connectpath, strerror(errno)); status = NT_STATUS_UNSUCCESSFUL; goto err_root_exit; } /* Any error exit after here needs to call the disconnect hook. */ on_err_call_dis_hook = true; if ((!conn->printer) && (!conn->ipc) && lp_change_notify()) { if (sconn->notify_ctx == NULL) { sconn->notify_ctx = notify_init( sconn, sconn->msg_ctx, sconn->ev_ctx); status = messaging_register( sconn->msg_ctx, sconn, MSG_SMB_NOTIFY_CANCEL_DELETED, smbd_notify_cancel_deleted); } if (sconn->sys_notify_ctx == NULL) { sconn->sys_notify_ctx = sys_notify_context_create( sconn, sconn->ev_ctx); } } if (lp_kernel_oplocks(snum)) { init_kernel_oplocks(conn->sconn); } /* * Fix compatibility issue pointed out by Volker. * We pass the conn->connectpath to the preexec * scripts as a parameter, so attempt to canonicalize * it here before calling the preexec scripts. * We ignore errors here, as it is possible that * the conn->connectpath doesn't exist yet and * the preexec scripts will create them. */ (void)canonicalize_connect_path(conn); /* Preexecs are done here as they might make the dir we are to ChDir * to below */ /* execute any "root preexec = " line */ if (*lp_root_preexec(talloc_tos(), snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), lp_servicename(talloc_tos(), SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, lp_root_preexec(talloc_tos(), snum)); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_root_preexec_close(snum)) { DEBUG(1,("root preexec gave %d - failing " "connection\n", ret)); status = NT_STATUS_ACCESS_DENIED; goto err_root_exit; } } /* USER Activites: */ if (!change_to_user(conn, conn->vuid)) { /* No point continuing if they fail the basic checks */ DEBUG(0,("Can't become connected user!\n")); status = NT_STATUS_LOGON_FAILURE; goto err_root_exit; } effuid = geteuid(); effgid = getegid(); /* Remember that a different vuid can connect later without these * checks... */ /* Preexecs are done here as they might make the dir we are to ChDir * to below */ /* execute any "preexec = " line */ if (*lp_preexec(talloc_tos(), snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), lp_servicename(talloc_tos(), SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, lp_preexec(talloc_tos(), snum)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_preexec_close(snum)) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); status = NT_STATUS_ACCESS_DENIED; goto err_root_exit; } } #ifdef WITH_FAKE_KASERVER if (lp_afs_share(snum)) { afs_login(conn); } #endif /* * we've finished with the user stuff - go back to root * so the SMB_VFS_STAT call will only fail on path errors, * not permission problems. */ change_to_root_user(); /* ROOT Activites: */ /* * If widelinks are disallowed we need to canonicalise the connect * path here to ensure we don't have any symlinks in the * connectpath. We will be checking all paths on this connection are * below this directory. We must do this after the VFS init as we * depend on the realpath() pointer in the vfs table. JRA. */ if (!lp_widelinks(snum)) { if (!canonicalize_connect_path(conn)) { DEBUG(0, ("canonicalize_connect_path failed " "for service %s, path %s\n", lp_servicename(talloc_tos(), snum), conn->connectpath)); status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } } /* Add veto/hide lists */ if (!IS_IPC(conn) && !IS_PRINT(conn)) { set_namearray( &conn->veto_list, lp_veto_files(talloc_tos(), snum)); set_namearray( &conn->hide_list, lp_hide_files(talloc_tos(), snum)); set_namearray( &conn->veto_oplock_list, lp_veto_oplock_files(talloc_tos(), snum)); set_namearray( &conn->aio_write_behind_list, lp_aio_write_behind(talloc_tos(), snum)); } smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath, NULL, NULL); if (smb_fname_cpath == NULL) { status = NT_STATUS_NO_MEMORY; goto err_root_exit; } /* win2000 does not check the permissions on the directory during the tree connect, instead relying on permission check during individual operations. To match this behaviour I have disabled this chdir check (tridge) */ /* the alternative is just to check the directory exists */ if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 || !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to " "[%s]\n", conn->connectpath, lp_servicename(talloc_tos(), snum))); } else { DEBUG(0,("'%s' does not exist or permission denied " "when connecting to [%s] Error was %s\n", conn->connectpath, lp_servicename(talloc_tos(), snum), strerror(errno) )); } status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } conn->base_share_dev = smb_fname_cpath->st.st_ex_dev; talloc_free(conn->origpath); conn->origpath = talloc_strdup(conn, conn->connectpath); /* Figure out the characteristics of the underlying filesystem. This * assumes that all the filesystem mounted withing a share path have * the same characteristics, which is likely but not guaranteed. */ conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); /* * Print out the 'connected as' stuff here as we need * to know the effective uid and gid we will be using * (at least initially). */ if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) { dbgtext( "%s (%s) ", get_remote_machine_name(), tsocket_address_string(conn->sconn->remote_address, talloc_tos()) ); dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : ""); dbgtext( "connect to service %s ", lp_servicename(talloc_tos(), snum) ); dbgtext( "initially as user %s ", conn->session_info->unix_info->unix_name ); dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid ); dbgtext( "(pid %d)\n", (int)getpid() ); } return status; err_root_exit: TALLOC_FREE(smb_fname_cpath); /* We must exit this function as root. */ if (geteuid() != 0) { change_to_root_user(); } if (on_err_call_dis_hook) { /* Call VFS disconnect hook */ SMB_VFS_DISCONNECT(conn); } return status; }
static int rsync_module(int fd, int i) { int argc=0; char *argv[MAX_ARGS]; char **argp; char line[MAXPATHLEN]; uid_t uid = (uid_t)-2; gid_t gid = (gid_t)-2; char *p; char *addr = client_addr(fd); char *host = client_name(fd); char *name = lp_name(i); int use_chroot = lp_use_chroot(i); int start_glob=0; int ret; char *request=NULL; extern int am_sender; extern int remote_version; extern int am_root; if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) { rprintf(FERROR,"rsync denied on module %s from %s (%s)\n", name, client_name(fd), client_addr(fd)); io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n", name, client_name(fd), client_addr(fd)); return -1; } if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) { if (errno) { rprintf(FERROR,"failed to open lock file %s : %s\n", lp_lock_file(i), strerror(errno)); io_printf(fd,"@ERROR: failed to open lock file %s : %s\n", lp_lock_file(i), strerror(errno)); } else { rprintf(FERROR,"max connections (%d) reached\n", lp_max_connections(i)); io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i)); } return -1; } auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD "); if (!auth_user) { rprintf(FERROR,"auth failed on module %s from %s (%s)\n", name, client_name(fd), client_addr(fd)); io_printf(fd,"@ERROR: auth failed on module %s\n",name); return -1; } module_id = i; if (lp_read_only(i)) read_only = 1; am_root = (getuid() == 0); if (am_root) { p = lp_uid(i); if (!name_to_uid(p, &uid)) { if (!isdigit(*p)) { rprintf(FERROR,"Invalid uid %s\n", p); io_printf(fd,"@ERROR: invalid uid\n"); return -1; } uid = atoi(p); } p = lp_gid(i); if (!name_to_gid(p, &gid)) { if (!isdigit(*p)) { rprintf(FERROR,"Invalid gid %s\n", p); io_printf(fd,"@ERROR: invalid gid\n"); return -1; } gid = atoi(p); } } p = lp_include_from(i); add_exclude_file(p, 1, 1); p = lp_include(i); add_include_line(p); p = lp_exclude_from(i); add_exclude_file(p, 1, 0); p = lp_exclude(i); add_exclude_line(p); log_open(); if (use_chroot) { if (chroot(lp_path(i))) { rprintf(FERROR,"chroot %s failed\n", lp_path(i)); io_printf(fd,"@ERROR: chroot failed\n"); return -1; } if (!push_dir("/", 0)) { rprintf(FERROR,"chdir %s failed\n", lp_path(i)); io_printf(fd,"@ERROR: chdir failed\n"); return -1; } } else { if (!push_dir(lp_path(i), 0)) { rprintf(FERROR,"chdir %s failed\n", lp_path(i)); io_printf(fd,"@ERROR: chdir failed\n"); return -1; } } if (am_root) { if (setgid(gid)) { rprintf(FERROR,"setgid %d failed\n", gid); io_printf(fd,"@ERROR: setgid failed\n"); return -1; } if (setuid(uid)) { rprintf(FERROR,"setuid %d failed\n", uid); io_printf(fd,"@ERROR: setuid failed\n"); return -1; } am_root = (getuid() == 0); } io_printf(fd,"@RSYNCD: OK\n"); argv[argc++] = "rsyncd"; while (1) { if (!read_line(fd, line, sizeof(line)-1)) { return -1; } if (!*line) break; p = line; argv[argc] = strdup(p); if (!argv[argc]) { return -1; } if (start_glob) { if (start_glob == 1) { request = strdup(p); start_glob++; } glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot); } else { argc++; } if (strcmp(line,".") == 0) { start_glob = 1; } if (argc == MAX_ARGS) { return -1; } } if (!use_chroot) { /* * Note that this is applied to all parameters, whether or not * they are filenames, but no other legal parameters contain * the forms that need to be sanitized so it doesn't hurt; * it is not known at this point which parameters are files * and which aren't. */ for (i = 1; i < argc; i++) { sanitize_path(argv[i]); } } ret = parse_arguments(argc, argv, 0); if (request) { if (*auth_user) { rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n", am_sender?"on":"to", request, auth_user, host, addr); } else { rprintf(FINFO,"rsync %s %s from %s (%s)\n", am_sender?"on":"to", request, host, addr); } free(request); } #if !TRIDGE /* don't allow the logs to be flooded too fast */ if (verbose > 1) verbose = 1; #endif argc -= optind; argp = argv + optind; optind = 0; if (remote_version > 17 && am_sender) io_start_multiplex_out(fd); if (!ret) { option_error(); } if (lp_timeout(i)) { extern int io_timeout; io_timeout = lp_timeout(i); } start_server(fd, fd, argc, argp); return 0; }
uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p, struct fss_AddToShadowCopySet *r) { uint32_t ret; struct fss_sc_set *sc_set; struct fss_sc *sc; struct fss_sc_smap *sc_smap; int snum; char *service; char *base_vol; char *share; char *path_name; struct connection_struct *conn; NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_out; } if (!fss_permitted(p)) { ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_tmp_free; } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { ret = HRES_ERROR_V(HRES_E_INVALIDARG); goto err_tmp_free; } status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share); if (!NT_STATUS_IS_OK(status)) { ret = fss_ntstatus_map(status); goto err_tmp_free; } snum = find_service(tmp_ctx, share, &service); if ((snum == -1) || (service == NULL)) { DEBUG(0, ("share at %s not found\n", r->in.ShareName)); ret = HRES_ERROR_V(HRES_E_INVALIDARG); goto err_tmp_free; } path_name = lp_path(tmp_ctx, snum); if (path_name == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_tmp_free; } status = fss_vfs_conn_create(tmp_ctx, server_event_context(), p->msg_ctx, p->session_info, snum, &conn); if (!NT_STATUS_IS_OK(status)) { ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_tmp_free; } if (!become_user_by_session(conn, p->session_info)) { DEBUG(0, ("failed to become user\n")); fss_vfs_conn_destroy(conn); ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_tmp_free; } status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol); unbecome_user(); fss_vfs_conn_destroy(conn); if (!NT_STATUS_IS_OK(status)) { ret = FSRVP_E_NOT_SUPPORTED; goto err_tmp_free; } if ((sc_set->state != FSS_SC_STARTED) && (sc_set->state != FSS_SC_ADDED)) { ret = FSRVP_E_BAD_STATE; goto err_tmp_free; } /* stop msg seq timer */ TALLOC_FREE(fss_global.seq_tmr); /* * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList * where ShadowCopy.VolumeName matches the file store on which the * share identified by ShareName is hosted. If an entry is found, the * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS. * If no entry is found, the server MUST create a new ShadowCopy * object * XXX Windows appears to allow multiple mappings for the same vol! */ sc = sc_lookup_volname(sc_set->scs, base_vol); if (sc != NULL) { ret = FSRVP_E_OBJECT_ALREADY_EXISTS; goto err_tmr_restart; } sc = talloc_zero(sc_set, struct fss_sc); if (sc == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_tmr_restart; } talloc_steal(sc, base_vol); sc->volume_name = base_vol; sc->sc_set = sc_set; sc->create_ts = time(NULL); sc->id = GUID_random(); /* Windows servers ignore client ids */ sc->id_str = GUID_string(sc, &sc->id); if (sc->id_str == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_sc_free; } sc_smap = talloc_zero(sc, struct fss_sc_smap); if (sc_smap == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_sc_free; } talloc_steal(sc_smap, service); sc_smap->share_name = service; sc_smap->is_exposed = false; /* * generate the sc_smap share name now. It is a unique identifier for * the smap used as a tdb key for state storage. */ ret = map_share_name(sc_smap, sc); if (ret) { goto err_sc_free; } /* add share map to shadow-copy */ DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *); sc->smaps_count++; /* add shadow-copy to shadow-copy set */ DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *); sc_set->scs_count++; DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n", sc->volume_name, sc_set->id_str)); /* start the Message Sequence Timer with timeout of 1800 seconds */ fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr); sc_set->state = FSS_SC_ADDED; r->out.pShadowCopyId = &sc->id; talloc_free(tmp_ctx); return 0; err_sc_free: talloc_free(sc); err_tmr_restart: fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr); err_tmp_free: talloc_free(tmp_ctx); err_out: return ret; }