Example #1
0
void
die_mail_pame(cl_t * cl, int pamerrno, struct passwd *pas, char *str,
              env_list_t * env)
/* log an error in syslog, mail user if necessary, and die */
{
    char buf[MAX_MSG];

    snprintf(buf, sizeof(buf), "%s for user '%s'", str, pas->pw_name);

    if (is_mail(cl->cl_option)) {
        char **envp = env_list_export_envp(env);
        FILE *mailf =
            create_mail(cl, "Could not run fcron job", NULL, NULL, envp);

        /* print the error in both syslog and a file, in order to mail it to user */
        if (dup2(fileno(mailf), 1) != 1 || dup2(1, 2) != 2)
            die_e("dup2() error");      /* dup2 also clears close-on-exec flag */

        foreground = 1;
        error_pame(pamh, pamerrno, buf, cl->cl_shell);
        error("Job '%s' has *not* run.", cl->cl_shell);
        foreground = 0;

        pam_end(pamh, pamerrno);

        become_user(cl, pas, "/");

        launch_mailer(cl, mailf, envp);
        /* launch_mailer() does not return : we never get here */
    }
    else
        die_pame(pamh, pamerrno, buf, cl->cl_shell);
}
Example #2
0
/* BTW, in case you're wondering, this returns void* so that
 * it can be used as a pthread... 
 */
static void *default_start_server(void *arg)
{
	server_t self = arg;
	connection_t con;
	int i;

	if (!self) return NULL;

	/* 
	 * TODO.
	 * This shouldn't be done here. It doesn't really matter
	 * because it is basically a no-op right now anyway.
	 * A single process can have several servers running 
	 * in it, conceivably.
	 *
	 * Maybe it should be moved to ag.c and left up to main.
	 */
	become_daemon(self);


	/* configure the wait_queue's max size */
	self->wq->max = self->maxcon;

	/* this is the connection handler: */
	self->handlers = ag_malloc(sizeof(handler_rec) * self->numthreads);

	for (i = 0; i < self->numthreads; i++) {
		handler_t hd;
		hd = self->newhandler();
		hd->svr = self;
		self->handlers[i].hd = hd;
		(void) pthread_create(&self->handlers[i].tid,  /* thread id */
				      NULL,                   /* attributes */
				      hd->start,              /* function to run */
				      (void *)hd              /* arg to pass to function */
			);
	}

	/* 
	 * must do this before changing uids, because we may want to bind
	 * to a port < 1024 and then become a non-root user.
	 *
	 * TODO
	 * At this point we should also open up the logfile.
	*/
	self->listen_sk = setup_connection(self);

	/* only change users if self->uid is non-zero (non-root) */
	if (self->uid) become_user(self);

	for (;;) {
		con = accept_connection(self->listen_sk);
		if (!self->wq->add_con(self->wq, con)) con->destroy(con);
	}
}
Example #3
0
void test_become_user(void **state)
{
    struct passwd *sssd;
    errno_t ret;
    pid_t pid, wpid;
    int status;

    /* Must root as root, real or fake */
    assert_int_equal(geteuid(), 0);

    sssd = getpwnam("sssd");
    assert_non_null(sssd);

    pid = fork();
    if (pid == 0) {
        /* Change the UID in a child */
        ret = become_user(sssd->pw_uid, sssd->pw_gid);
        assert_int_equal(ret, EOK);

        /* Make sure we have the requested UID and GID now and there
         * are no supplementary groups
         */
        assert_int_equal(geteuid(), sssd->pw_uid);
        assert_int_equal(getegid(), sssd->pw_gid);
        assert_int_equal(getuid(), sssd->pw_uid);
        assert_int_equal(getgid(), sssd->pw_gid);

        /* Another become_user is a no-op */
        ret = become_user(sssd->pw_uid, sssd->pw_gid);
        assert_int_equal(ret, EOK);

        assert_int_equal(getgroups(0, NULL), 0);
        exit(0);
    }

    assert_int_not_equal(pid, -1);

    wpid = waitpid(pid, &status, 0);
    assert_int_equal(wpid, pid);
    assert_true(WIFEXITED(status));
    assert_int_equal(WEXITSTATUS(status), 0);
}
Example #4
0
void
change_user_setup_env(struct cl_t *cl,
                      char ***sendmailenv, char ***jobenv, char **curshell,
                      char **curhome, char **content_type, char **encoding)
/* call setup_user_and_env() and become_user().
 * As a result, *curshell and *curhome will be allocated and should thus be freed
 * if curshell and curhome are not NULL. */
{
    struct passwd *pas;

    errno = 0;
    pas = getpwnam(cl->cl_runas);
    if (pas == NULL)
        die_e("failed to get passwd fields for user \"%s\"", cl->cl_runas);

    setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome,
                       content_type, encoding);

    become_user(cl, pas, (curhome != NULL) ? *curhome : "/");
}
Example #5
0
/****************************************************************************
close a cnum
****************************************************************************/
void close_cnum(connection_struct *conn, uint16 vuid)
{
	DirCacheFlush(SNUM(conn));

	unbecome_user();

	DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
				 remote_machine,conn->client_address,
				 lp_servicename(SNUM(conn))));

	yield_connection(conn,
			 lp_servicename(SNUM(conn)),
			 lp_max_connections(SNUM(conn)));

	if (lp_status(SNUM(conn)))
		yield_connection(conn,"STATUS.",MAXSTATUS);

	file_close_conn(conn);
	dptr_closecnum(conn);

	/* execute any "postexec = " line */
	if (*lp_postexec(SNUM(conn)) && 
	    become_user(conn, vuid))  {
		pstring cmd;
		pstrcpy(cmd,lp_postexec(SNUM(conn)));
		standard_sub(conn,cmd);
		smbrun(cmd,NULL,False);
		unbecome_user();
	}

	unbecome_user();
	/* execute any "root postexec = " line */
	if (*lp_rootpostexec(SNUM(conn)))  {
		pstring cmd;
		pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
		standard_sub(conn,cmd);
		smbrun(cmd,NULL,False);
	}
	
	conn_free(conn);
}
Example #6
0
static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type)
{
	struct share_mode_lock *lck = 0;
	BOOL delete_dir = False;
	NTSTATUS status = NT_STATUS_OK;

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a directory also.
	 */

	lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name));
	}

	if (fsp->initial_delete_on_close) {
		BOOL became_user = False;

		/* Initial delete on close was set - for
		 * directories we don't care if anyone else
		 * wrote a real delete on close. */

		if (current_user.vuid != fsp->vuid) {
			become_user(fsp->conn, fsp->vuid);
			became_user = True;
		}
		send_stat_cache_delete_message(fsp->fsp_name);
		set_delete_on_close_lck(lck, True, &current_user.ut);
		if (became_user) {
			unbecome_user();
		}
	}

	delete_dir = lck->delete_on_close;

	if (delete_dir) {
		int i;
		/* See if others still have the dir open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->share_modes[i];
			if (is_valid_share_mode_entry(e)) {
				if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
					continue;
				}
				delete_dir = False;
				break;
			}
		}
	}

	if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
				delete_dir &&
				lck->delete_token) {
	
		/* Become the user who requested the delete. */

		if (!push_sec_ctx()) {
			smb_panic("close_directory: failed to push sec_ctx.\n");
		}

		set_sec_ctx(lck->delete_token->uid,
				lck->delete_token->gid,
				lck->delete_token->ngroups,
				lck->delete_token->groups,
				NULL);

		TALLOC_FREE(lck);

		status = rmdir_internals(fsp->conn, fsp->fsp_name);

		DEBUG(5,("close_directory: %s. Delete on close was set - "
			 "deleting directory returned %s.\n",
			 fsp->fsp_name, nt_errstr(status)));

		/* unbecome user. */
		pop_sec_ctx();

		/*
		 * Ensure we remove any change notify requests that would
		 * now fail as the directory has been deleted.
		 */

		if(NT_STATUS_IS_OK(status)) {
			remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
		}
	} else {
		TALLOC_FREE(lck);
		remove_pending_change_notify_requests_by_fid(
			fsp, NT_STATUS_OK);
	}

	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(fsp);
	return status;
}
Example #7
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
					enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	BOOL delete_file = False;
	struct share_mode_lock *lck;
	SMB_STRUCT_STAT sbuf;
	NTSTATUS status = NT_STATUS_OK;
	int ret;

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_remove_share_mode: Could not get share mode "
			  "lock for file %s\n", fsp->fsp_name));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_remove_share_mode: Could not delete share "
			  "entry for file %s\n", fsp->fsp_name));
	}

	if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
		BOOL became_user = False;

		/* Initial delete on close was set and no one else
		 * wrote a real delete on close. */

		if (current_user.vuid != fsp->vuid) {
			become_user(conn, fsp->vuid);
			became_user = True;
		}
		set_delete_on_close_lck(lck, True, &current_user.ut);
		if (became_user) {
			unbecome_user();
		}
	}

	delete_file = lck->delete_on_close;

	if (delete_file) {
		int i;
		/* See if others still have the file open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->share_modes[i];
			if (is_valid_share_mode_entry(e)) {
				if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
					continue;
				}
				delete_file = False;
				break;
			}
		}
	}

	/* Notify any deferred opens waiting on this close. */
	notify_deferred_opens(lck);
	reply_to_oplock_break_requests(fsp);

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
	    || !delete_file
	    || (lck->delete_token == NULL)) {
		TALLOC_FREE(lck);
		return NT_STATUS_OK;
	}

	/*
	 * Ok, we have to delete the file
	 */

	DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
		 "- deleting file.\n", fsp->fsp_name));

	/* Become the user who requested the delete. */

	if (!push_sec_ctx()) {
		smb_panic("close_remove_share_mode: file %s. failed to push "
			  "sec_ctx.\n");
	}

	set_sec_ctx(lck->delete_token->uid,
		    lck->delete_token->gid,
		    lck->delete_token->ngroups,
		    lck->delete_token->groups,
		    NULL);

	/* We can only delete the file if the name we have is still valid and
	   hasn't been renamed. */

	if (fsp->posix_open) {
		ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf);
	} else {
		ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf);
	}

	if (ret != 0) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and stat failed with error %s\n",
			 fsp->fsp_name, strerror(errno) ));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if(sbuf.st_dev != fsp->dev || sbuf.st_ino != fsp->inode) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and dev and/or inode does not match\n",
			 fsp->fsp_name ));
		DEBUG(5,("close_remove_share_mode: file %s. stored dev = %x, "
			 "inode = %.0f stat dev = %x, inode = %.0f\n",
			 fsp->fsp_name,
			 (unsigned int)fsp->dev, (double)fsp->inode,
			 (unsigned int)sbuf.st_dev, (double)sbuf.st_ino ));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if (SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
		/*
		 * This call can potentially fail as another smbd may
		 * have had the file open with delete on close set and
		 * deleted it when its last reference to this file
		 * went away. Hence we log this but not at debug level
		 * zero.
		 */

		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and unlink failed with error %s\n",
			 fsp->fsp_name, strerror(errno) ));

		status = map_nt_error_from_unix(errno);
	}

	notify_fname(conn, NOTIFY_ACTION_REMOVED,
		     FILE_NOTIFY_CHANGE_FILE_NAME,
		     fsp->fsp_name);

	/* As we now have POSIX opens which can unlink
 	 * with other open files we may have taken
 	 * this code path with more than one share mode
 	 * entry - ensure we only delete once by resetting
 	 * the delete on close flag. JRA.
 	 */

	set_delete_on_close_lck(lck, False, NULL);

 done:

	/* unbecome user. */
	pop_sec_ctx();
	
	TALLOC_FREE(lck);
	return status;
}
Example #8
0
File: upslog.c Project: alezz/nut
int main(int argc, char **argv)
{
	int	interval = 30, i;
	const char	*prog = xbasename(argv[0]);
	time_t	now, nextpoll = 0;
	const char	*user = NULL;
	struct passwd	*new_uid = NULL;
	const char	*pidfilebase = prog;

	logformat = DEFAULT_LOGFORMAT;
	user = RUN_AS_USER;

	printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);

	 while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:")) != -1) {
		switch(i) {
			case 'h':
				help(prog);
				break;

			case 's':
				monhost = optarg;
				break;

			case 'l':
				logfn = optarg;
				break;

			case 'i':
				interval = atoi(optarg);
				break;

			case 'f':
				logformat = optarg;
				break;

			case 'u':
				user = optarg;
				break;

			case 'V':
				exit(EXIT_SUCCESS);

			case 'p':
				pidfilebase = optarg;
				break;
		}
	}

	argc -= optind;
	argv += optind;

	/* not enough args for the old way? */
	if ((argc == 1) || (argc == 2))
		help(prog);

	/* see if it's being called in the old style - 3 or 4 args */

	/* <system> <logfn> <interval> [<format>] */

	if (argc >= 3) {
		monhost = argv[0];
		logfn = argv[1];
		interval = atoi(argv[2]);
	}

	if (argc >= 4) {
		/* read out the remaining argv entries to the format string */

		logformat = xmalloc(LARGEBUF);
		memset(logformat, '\0', LARGEBUF);

		for (i = 3; i < argc; i++)
			snprintfcat(logformat, LARGEBUF, "%s ", argv[i]);
	}

	if (!monhost)
		fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s <system>");

	if (!logfn)
		fatalx(EXIT_FAILURE, "No filename defined for logging - use -l <file>");

	/* shouldn't happen */
	if (!logformat)
		fatalx(EXIT_FAILURE, "No format defined - but this should be impossible");

	printf("logging status of %s to %s (%is intervals)\n", 
		monhost, logfn, interval);

	if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) {
		fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  Required format: upsname[@hostname[:port]]\n");
	}

	if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0)
		fprintf(stderr, "Warning: initial connect failed: %s\n", 
			upscli_strerror(&ups));

	if (strcmp(logfn, "-") == 0)
		logfile = stdout;
	else
		logfile = fopen(logfn, "a");

	if (logfile == NULL)
		fatal_with_errno(EXIT_FAILURE, "could not open logfile %s", logfn);

	/* now drop root if we have it */
	new_uid = get_user_pwent(user);

	open_syslog(prog); 

	if (logfile != stdout)
		background();

	setup_signals();

	writepid(pidfilebase);

	become_user(new_uid);

	compile_format();

	while (exit_flag == 0) {
		time(&now);

		if (nextpoll > now) {
			/* there is still time left, so sleep it off */
			sleep(difftime(nextpoll, now));
			nextpoll += interval;
		} else {
			/* we spent more time in polling than the interval allows */
			nextpoll = now + interval;
		}

		if (reopen_flag) {
			upslogx(LOG_INFO, "Signal %d: reopening log file", 
				reopen_flag);
			reopen_log();
			reopen_flag = 0;
		}

		/* reconnect if necessary */
		if (upscli_fd(&ups) < 0) {
			upscli_connect(&ups, hostname, port, 0);
		}

		run_flist();

		/* don't keep connection open if we don't intend to use it shortly */
		if (interval > 30) {
			upscli_disconnect(&ups);
		}
	}

	upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);

	if (logfile != stdout)
		fclose(logfile);

	upscli_disconnect(&ups);
	
	exit(EXIT_SUCCESS);
}
Example #9
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
                                        enum file_close_type close_type)
{
    connection_struct *conn = fsp->conn;
    bool delete_file = false;
    bool changed_user = false;
    struct share_mode_lock *lck = NULL;
    NTSTATUS status = NT_STATUS_OK;
    NTSTATUS tmp_status;
    struct file_id id;

    /* Ensure any pending write time updates are done. */
    if (fsp->update_write_time_event) {
        update_write_time_handler(smbd_event_context(),
                                  fsp->update_write_time_event,
                                  timeval_current(),
                                  (void *)fsp);
    }

    /*
     * Lock the share entries, and determine if we should delete
     * on close. If so delete whilst the lock is still in effect.
     * This prevents race conditions with the file being created. JRA.
     */

    lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
                              NULL);

    if (lck == NULL) {
        DEBUG(0, ("close_remove_share_mode: Could not get share mode "
                  "lock for file %s\n", fsp_str_dbg(fsp)));
        status = NT_STATUS_INVALID_PARAMETER;
        goto done;
    }

    if (fsp->write_time_forced) {
        DEBUG(10,("close_remove_share_mode: write time forced "
                  "for file %s\n",
                  fsp_str_dbg(fsp)));
        set_close_write_time(fsp, lck->changed_write_time);
    } else if (fsp->update_write_time_on_close) {
        /* Someone had a pending write. */
        if (null_timespec(fsp->close_write_time)) {
            DEBUG(10,("close_remove_share_mode: update to current time "
                      "for file %s\n",
                      fsp_str_dbg(fsp)));
            /* Update to current time due to "normal" write. */
            set_close_write_time(fsp, timespec_current());
        } else {
            DEBUG(10,("close_remove_share_mode: write time pending "
                      "for file %s\n",
                      fsp_str_dbg(fsp)));
            /* Update to time set on close call. */
            set_close_write_time(fsp, fsp->close_write_time);
        }
    }

    if (!del_share_mode(lck, fsp)) {
        DEBUG(0, ("close_remove_share_mode: Could not delete share "
                  "entry for file %s\n",
                  fsp_str_dbg(fsp)));
    }

    if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
        bool became_user = False;

        /* Initial delete on close was set and no one else
         * wrote a real delete on close. */

        if (current_user.vuid != fsp->vuid) {
            become_user(conn, fsp->vuid);
            became_user = True;
        }
        fsp->delete_on_close = true;
        set_delete_on_close_lck(lck, True, &current_user.ut);
        if (became_user) {
            unbecome_user();
        }
    }

    delete_file = lck->delete_on_close;

    if (delete_file) {
        int i;
        /* See if others still have the file open. If this is the
         * case, then don't delete. If all opens are POSIX delete now. */
        for (i=0; i<lck->num_share_modes; i++) {
            struct share_mode_entry *e = &lck->share_modes[i];
            if (is_valid_share_mode_entry(e)) {
                if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
                    continue;
                }
                delete_file = False;
                break;
            }
        }
    }

    /* Notify any deferred opens waiting on this close. */
    notify_deferred_opens(lck);
    reply_to_oplock_break_requests(fsp);

    /*
     * NT can set delete_on_close of the last open
     * reference to a file.
     */

    if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
            || !delete_file
            || (lck->delete_token == NULL)) {
        TALLOC_FREE(lck);
        return NT_STATUS_OK;
    }

    /*
     * Ok, we have to delete the file
     */

    DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
             "- deleting file.\n", fsp_str_dbg(fsp)));

    /*
     * Don't try to update the write time when we delete the file
     */
    fsp->update_write_time_on_close = false;

    if (!unix_token_equal(lck->delete_token, &current_user.ut)) {
        /* Become the user who requested the delete. */

        DEBUG(5,("close_remove_share_mode: file %s. "
                 "Change user to uid %u\n",
                 fsp_str_dbg(fsp),
                 (unsigned int)lck->delete_token->uid));

        if (!push_sec_ctx()) {
            smb_panic("close_remove_share_mode: file %s. failed to push "
                      "sec_ctx.\n");
        }

        set_sec_ctx(lck->delete_token->uid,
                    lck->delete_token->gid,
                    lck->delete_token->ngroups,
                    lck->delete_token->groups,
                    NULL);

        changed_user = true;
    }

    /* We can only delete the file if the name we have is still valid and
       hasn't been renamed. */

    tmp_status = vfs_stat_fsp(fsp);
    if (!NT_STATUS_IS_OK(tmp_status)) {
        DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
                 "was set and stat failed with error %s\n",
                 fsp_str_dbg(fsp), nt_errstr(tmp_status)));
        /*
         * Don't save the errno here, we ignore this error
         */
        goto done;
    }

    id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);

    if (!file_id_equal(&fsp->file_id, &id)) {
        DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
                 "was set and dev and/or inode does not match\n",
                 fsp_str_dbg(fsp)));
        DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
                 "stat file_id %s\n",
                 fsp_str_dbg(fsp),
                 file_id_string_tos(&fsp->file_id),
                 file_id_string_tos(&id)));
        /*
         * Don't save the errno here, we ignore this error
         */
        goto done;
    }

    if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
            && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

        status = delete_all_streams(conn, fsp->fsp_name->base_name);

        if (!NT_STATUS_IS_OK(status)) {
            DEBUG(5, ("delete_all_streams failed: %s\n",
                      nt_errstr(status)));
            goto done;
        }
    }


    if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
        /*
         * This call can potentially fail as another smbd may
         * have had the file open with delete on close set and
         * deleted it when its last reference to this file
         * went away. Hence we log this but not at debug level
         * zero.
         */

        DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
                 "was set and unlink failed with error %s\n",
                 fsp_str_dbg(fsp), strerror(errno)));

        status = map_nt_error_from_unix(errno);
    }

    notify_fname(conn, NOTIFY_ACTION_REMOVED,
                 FILE_NOTIFY_CHANGE_FILE_NAME,
                 fsp->fsp_name->base_name);

    /* As we now have POSIX opens which can unlink
     * with other open files we may have taken
     * this code path with more than one share mode
     * entry - ensure we only delete once by resetting
     * the delete on close flag. JRA.
     */

    fsp->delete_on_close = false;
    set_delete_on_close_lck(lck, False, NULL);

done:

    if (changed_user) {
        /* unbecome user. */
        pop_sec_ctx();
    }

    TALLOC_FREE(lck);
    return status;
}
Example #10
0
/****************************************************************************
  make a connection to a service
****************************************************************************/
connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
{
	int snum;
	struct passwd *pass = NULL;
	BOOL guest = False;
	BOOL force = False;
	extern int Client;
	connection_struct *conn;
	int ret;

	strlower(service);

	snum = find_service(service);
	if (snum < 0) {
		extern int Client;
		if (strequal(service,"IPC$")) {
			DEBUG(3,("refusing IPC connection\n"));
			*ecode = ERRnoipc;
			return NULL;
		}

		DEBUG(0,("%s (%s) couldn't find service %s\n",
			 remote_machine, client_addr(Client), service));
		*ecode = ERRinvnetname;
		return NULL;
	}

	if (strequal(service,HOMES_NAME)) {
		if (*user && Get_Pwnam(user,True)) {
			fstring dos_username;
			fstrcpy(dos_username, user);
			unix_to_dos(dos_username, True);
			return(make_connection(dos_username,user,password,
					       pwlen,dev,vuid,ecode));
		}

		if(lp_security() != SEC_SHARE) {
			if (validated_username(vuid)) {
				fstring dos_username;
				fstrcpy(user,validated_username(vuid));
				fstrcpy(dos_username, user);
				unix_to_dos(dos_username, True);
				return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
			}
		} else {
			/* Security = share. Try with sesssetup_user
			 * as the username.  */
			if(*sesssetup_user) {
				fstring dos_username;
				fstrcpy(user,sesssetup_user);
				fstrcpy(dos_username, user);
				unix_to_dos(dos_username, True);
				return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
			}
		}
	}

	if (!lp_snum_ok(snum) || 
	    !check_access(Client, 
			  lp_hostsallow(snum), lp_hostsdeny(snum))) {    
		*ecode = ERRaccess;
		return NULL;
	}

	/* you can only connect to the IPC$ service as an ipc device */
	if (strequal(service,"IPC$"))
		pstrcpy(dev,"IPC");
	
	if (*dev == '?' || !*dev) {
		if (lp_print_ok(snum)) {
			pstrcpy(dev,"LPT1:");
		} else {
			pstrcpy(dev,"A:");
		}
	}

	/* if the request is as a printer and you can't print then refuse */
	strupper(dev);
	if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
		DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
		*ecode = ERRinvdevice;
		return NULL;
	}

	/* lowercase the user name */
	strlower(user);

	/* add it as a possible user name */
	add_session_user(service);

	/* shall we let them in? */
	if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
		DEBUG( 2, ( "Invalid username/password for %s\n", service ) );
		*ecode = ERRbadpw;
		return NULL;
	}
  
	conn = conn_new();
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*ecode = ERRnoresource;
		conn_free(conn);
		return NULL;
	}

	/* find out some info about the user */
	pass = Get_Pwnam(user,True);

	if (pass == NULL) {
		DEBUG(0,( "Couldn't find account %s\n",user));
		*ecode = ERRbaduid;
		conn_free(conn);
		return NULL;
	}

	conn->read_only = lp_readonly(snum);

	{
		pstring list;
		StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
		pstring_sub(list,"%S",service);

		if (user_in_list(user,list))
			conn->read_only = True;
		
		StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
		pstring_sub(list,"%S",service);
		
		if (user_in_list(user,list))
			conn->read_only = False;    
	}

	/* admin user check */
	
	/* JRA - original code denied admin user if the share was
	   marked read_only. Changed as I don't think this is needed,
	   but old code left in case there is a problem here.
	*/
	if (user_in_list(user,lp_admin_users(snum)) 
#if 0
	    && !conn->read_only
#endif
	    ) {
		conn->admin_user = True;
		DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
	} else {
		conn->admin_user = False;
	}
    
	conn->force_user = force;
	conn->vuid = vuid;
	conn->uid = pass->pw_uid;
	conn->gid = pass->pw_gid;
	safe_strcpy(conn->client_address, client_addr(Client), sizeof(conn->client_address)-1);
	conn->num_files_open = 0;
	conn->lastused = time(NULL);
	conn->service = snum;
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = (strncmp(dev,"IPC",3) == 0);
	conn->dirptr = NULL;
	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	string_set(&conn->dirpath,"");
	string_set(&conn->user,user);
	
	/*
	 * If force user is true, then store the
	 * given userid and also the primary groupid
	 * of the user we're forcing.
	 */
	
	if (*lp_force_user(snum)) {
		struct passwd *pass2;
		pstring fuser;
		pstrcpy(fuser,lp_force_user(snum));

		/* Allow %S to be used by force user. */
		pstring_sub(fuser,"%S",service);

		pass2 = (struct passwd *)Get_Pwnam(fuser,True);
		if (pass2) {
			conn->uid = pass2->pw_uid;
			conn->gid = pass2->pw_gid;
			string_set(&conn->user,fuser);
			fstrcpy(user,fuser);
			conn->force_user = True;
			DEBUG(3,("Forced user %s\n",fuser));	  
		} else {
			DEBUG(1,("Couldn't find user %s\n",fuser));
		}
	}

#ifdef HAVE_GETGRNAM 
	/*
	 * If force group is true, then override
	 * any groupid stored for the connecting user.
	 */
	
	if (*lp_force_group(snum)) {
		struct group *gptr;
		pstring gname;
		pstring tmp_gname;
		BOOL user_must_be_member = False;
		
		StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);

		if (tmp_gname[0] == '+') {
			user_must_be_member = True;
			StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
		} else {
			StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
		}
		/* default service may be a group name 		*/
		pstring_sub(gname,"%S",service);
		gptr = (struct group *)getgrnam(gname);
		
		if (gptr) {
			/*
			 * 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 (conn->force_user && user_must_be_member) {
				int i;
				for (i = 0; gptr->gr_mem[i] != NULL; i++) {
					if (strcmp(user,gptr->gr_mem[i]) == 0) {
						conn->gid = gptr->gr_gid;
						DEBUG(3,("Forced group %s for member %s\n",gname,user));
						break;
					}
				}
			} else {
				conn->gid = gptr->gr_gid;
				DEBUG(3,("Forced group %s\n",gname));
			}
		} else {
			DEBUG(1,("Couldn't find group %s\n",gname));
		}
	}
#endif /* HAVE_GETGRNAM */

	{
		pstring s;
		pstrcpy(s,lp_pathname(snum));
		standard_sub(conn,s);
		string_set(&conn->connectpath,s);
		DEBUG(3,("Connect path is %s\n",s));
	}

	/* groups stuff added by ih */
	conn->ngroups = 0;
	conn->groups = NULL;
	
	if (!IS_IPC(conn)) {
		/* Find all the groups this uid is in and
		   store them. Used by become_user() */
		setup_groups(conn->user,conn->uid,conn->gid,
			     &conn->ngroups,&conn->groups);
		
		/* check number of connections */
		if (!claim_connection(conn,
				      lp_servicename(SNUM(conn)),
				      lp_max_connections(SNUM(conn)),
				      False)) {
			DEBUG(1,("too many connections - rejected\n"));
			*ecode = ERRnoresource;
			conn_free(conn);
			return NULL;
		}  
		
		if (lp_status(SNUM(conn)))
			claim_connection(conn,"STATUS.",
					 MAXSTATUS,False);
	} /* IS_IPC */
	
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(SNUM(conn))) {
		pstring cmd;
		pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
		standard_sub(conn,cmd);
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL,False);
		if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
			DEBUG(1,("preexec gave %d - failing connection\n", ret));
			conn_free(conn);
			*ecode = ERRsrverror;
			return NULL;
		}
	}
	
	if (!become_user(conn, conn->vuid)) {
		DEBUG(0,("Can't become connected user!\n"));
		if (!IS_IPC(conn)) {
			yield_connection(conn,
					 lp_servicename(SNUM(conn)),
					 lp_max_connections(SNUM(conn)));
			if (lp_status(SNUM(conn))) {
				yield_connection(conn,"STATUS.",MAXSTATUS);
			}
		}
		conn_free(conn);
		*ecode = ERRbadpw;
		return NULL;
	}
	
	if (dos_ChDir(conn->connectpath) != 0) {
		DEBUG(0,("Can't change directory to %s (%s)\n",
			 conn->connectpath,strerror(errno)));
		unbecome_user();
		if (!IS_IPC(conn)) {
			yield_connection(conn,
					 lp_servicename(SNUM(conn)),
					 lp_max_connections(SNUM(conn)));
			if (lp_status(SNUM(conn))) 
				yield_connection(conn,"STATUS.",MAXSTATUS);
		}
		conn_free(conn);
		*ecode = ERRinvnetname;
		return NULL;
	}
	
	string_set(&conn->origpath,conn->connectpath);
	
#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early */
	{
		pstring s;
		pstrcpy(s,conn->connectpath);
		dos_GetWd(s);
		string_set(&conn->connectpath,s);
		dos_ChDir(conn->connectpath);
	}
#endif
	
	add_session_user(user);
		
	/* execute any "preexec = " line */
	if (*lp_preexec(SNUM(conn))) {
		pstring cmd;
		pstrcpy(cmd,lp_preexec(SNUM(conn)));
		standard_sub(conn,cmd);
		ret = smbrun(cmd,NULL,False);
		if (ret != 0 && lp_preexec_close(SNUM(conn))) {
			DEBUG(1,("preexec gave %d - failing connection\n", ret));
			conn_free(conn);
			*ecode = ERRsrverror;
			return NULL;
		}
	}

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using.
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", remote_machine, conn->client_address );
		dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
		dbgtext( "as user %s ", user );
		dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
		dbgtext( "(pid %d)\n", (int)getpid() );
	}
	
	/* we've finished with the sensitive stuff */
	unbecome_user();
	
	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
		set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
	}
	
	return(conn);
}
Example #11
0
int
run_job(struct exe_t *exeent)
    /* fork(), redirect outputs to a temp file, and execl() the task.
     * Return ERR if it could not fork() the first time, OK otherwise. */
{

    pid_t pid;
    cl_t *line = exeent->e_line;
    int pipe_pid_fd[2];
    int ret = 0;

    /* prepare the job execution */
    if (pipe(pipe_pid_fd) != 0) {
        error_e("pipe(pipe_pid_fd) : setting job_pid to -1");
        exeent->e_job_pid = -1;
        pipe_pid_fd[0] = pipe_pid_fd[1] = -1;
    }

#ifdef CHECKRUNJOB
    debug
        ("run_job(): first pipe created successfully : about to do first fork()");
#endif                          /* CHECKRUNJOB */

    switch (pid = fork()) {
    case -1:
        error_e("Fork error : could not exec '%s'", line->cl_shell);
        return ERR;
        break;

    case 0:
        /* child */
        {
            struct passwd *pas = NULL;
            char **jobenv = NULL;
            char **sendmailenv = NULL;
            char *curshell = NULL;
            char *curhome = NULL;
            char *content_type = NULL;
            char *encoding = NULL;
            FILE *mailf = NULL;
            int status = 0;
            int to_stdout = foreground && is_stdout(line->cl_option);
            int pipe_fd[2];
            short int mailpos = 0;      /* 'empty mail file' size */
#ifdef WITH_SELINUX
            int flask_enabled = is_selinux_enabled();
#endif

            /* // */
            debug("run_job(): child: %s, output to %s, %s, %s\n",
                  is_mail(line->cl_option) ? "mail" : "no mail",
                  to_stdout ? "stdout" : "file",
                  foreground ? "running in foreground" :
                  "running in background",
                  is_stdout(line->cl_option) ? "stdout" : "normal");
            /* // */

            errno = 0;
            pas = getpwnam(line->cl_runas);
            if (pas == NULL)
                die_e("failed to get passwd fields for user \"%s\"",
                      line->cl_runas);

            setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell,
                               &curhome, &content_type, &encoding);

            /* close unneeded READ fd */
            xclose_check(&(pipe_pid_fd[0]), "child's pipe_pid_fd[0]");

            pipe_fd[0] = pipe_fd[1] = -1;
            if (!to_stdout && is_mail(line->cl_option)) {
                /* we create the temp file (if needed) before change_user(),
                 * as temp_file() needs root privileges */
                /* if we run in foreground, stdout and stderr point to the console.
                 * Otherwise, stdout and stderr point to /dev/null . */
                mailf = create_mail(line, NULL, content_type, encoding, jobenv);
                mailpos = ftell(mailf);
                if (pipe(pipe_fd) != 0)
                    die_e("could not pipe() (job not executed)");
            }

            become_user(line, pas, curhome);
            Free_safe(curhome);

            /* restore umask to default */
            umask(saved_umask);

            sig_dfl();

#ifdef CHECKRUNJOB
            debug
                ("run_job(): child: change_user() done -- about to do 2nd fork()");
#endif                          /* CHECKRUNJOB */

            /* now, run the job */
            switch (pid = fork()) {
            case -1:
                error_e("Fork error : could not exec '%s'", line->cl_shell);
                if (write(pipe_pid_fd[1], &pid, sizeof(pid)) < 0)
                    error_e("could not write child pid to pipe_pid_fd[1]");
                xclose_check(&(pipe_fd[0]), "child's pipe_fd[0]");
                xclose_check(&(pipe_fd[1]), "child's pipe_fd[1]");
                xclose_check(&(pipe_pid_fd[1]), "child's pipe_pid_fd[1]");
                exit(EXIT_ERR);
                break;

            case 0:
                /* grand child (child of the 2nd fork) */

                /* the grand child does not use this pipe: close remaining fd */
                xclose_check(&(pipe_pid_fd[1]), "grand child's pipe_pid_fd[1]");

                if (!to_stdout)
                    /* note : the following closes the pipe */
                    run_job_grand_child_setup_stderr_stdout(line, pipe_fd);

                foreground = 1;
                /* now, errors will be mailed to the user (or to /dev/null) */

                run_job_grand_child_setup_nice(line);

                xcloselog();

#if defined(CHECKJOBS) || defined(CHECKRUNJOB)
                /* this will force to mail a message containing at least the exact
                 * and complete command executed for each execution of all jobs */
                debug("run_job(): grand-child: Executing \"%s -c %s\"",
                      curshell, line->cl_shell);
#endif                          /* CHECKJOBS OR CHECKRUNJOB */

#ifdef WITH_SELINUX
                if (flask_enabled
                    && setexeccon(line->cl_file->cf_user_context) < 0)
                    die_e("Can't set execute context '%s' for user '%s'.",
                          line->cl_file->cf_user_context, line->cl_runas);
#else
                if (setsid() == -1) {
                    die_e("setsid(): errno %d", errno);
                }
#endif
                execle(curshell, curshell, "-c", line->cl_shell, NULL, jobenv);
                /* execle returns only on error */
                die_e("Couldn't exec shell '%s'", curshell);

                /* execution never gets here */

            default:
                /* child (parent of the 2nd fork) */

                /* close unneeded WRITE pipe and READ pipe */
                xclose_check(&(pipe_fd[1]), "child's pipe_fd[1]");

#ifdef CHECKRUNJOB
                debug("run_job(): child: pipe_fd[1] and pipe_pid_fd[0] closed"
                      " -- about to write grand-child pid to pipe");
#endif                          /* CHECKRUNJOB */

                /* give the pid of the child to the parent (main) fcron process */
                ret = write_pipe(pipe_pid_fd[1], &pid, sizeof(pid));
                if (ret != OK) {
                    if (ret == ERR)
                        error
                            ("run_job(): child: Could not write job pid to pipe");
                    else {
                        errno = ret;
                        error_e
                            ("run_job(): child: Could not write job pid to pipe");
                    }
                }

#ifdef CHECKRUNJOB
                debug("run_job(): child: grand-child pid written to pipe");
#endif                          /* CHECKRUNJOB */

                if (!is_nolog(line->cl_option))
                    explain("Job '%s' started for user %s (pid %d)",
                            line->cl_shell, line->cl_file->cf_user, pid);

                if (!to_stdout && is_mail(line->cl_option)) {
                    /* user wants a mail : we use the pipe */
                    char mailbuf[TERM_LEN];
                    FILE *pipef = fdopen(pipe_fd[0], "r");

                    if (pipef == NULL)
                        die_e("Could not fdopen() pipe_fd[0]");

                    mailbuf[sizeof(mailbuf) - 1] = '\0';
                    while (fgets(mailbuf, sizeof(mailbuf), pipef) != NULL)
                        if (fputs(mailbuf, mailf) < 0)
                            warn("fputs() failed to write to mail file for job '%s' (pid %d)", line->cl_shell, pid);
                    /* (closes also pipe_fd[0]): */
                    xfclose_check(&pipef, "child's pipef");
                }

                /* FIXME : FOLLOWING HACK USELESS ? */
                /* FIXME : HACK
                 * this is a try to fix the bug on sorcerer linux (no jobs
                 * exectued at all, and
                 * "Could not read job pid : setting it to -1: No child processes"
                 * error messages) */
                /* use a select() or similar to know when parent has read
                 * the pid (with a timeout !) */
                /* // */
                sleep(2);
                /* // */
#ifdef CHECKRUNJOB
                debug("run_job(): child: closing pipe with parent");
#endif                          /* CHECKRUNJOB */
                xclose_check(&(pipe_pid_fd[1]), "child's pipe_pid_fd[1]");

                /* we use a while because of a possible interruption by a signal */
                while ((pid = wait3(&status, 0, NULL)) > 0) {
#ifdef CHECKRUNJOB
                    debug("run_job(): child: ending job pid %d", pid);
#endif                          /* CHECKRUNJOB */
                    end_job(line, status, mailf, mailpos, sendmailenv);
                }

                /* execution never gets here */

            }

            /* execution should never gets here, but if it happened we exit with an error */
            exit(EXIT_ERR);
        }

    default:
        /* parent */

        /* close unneeded WRITE fd */
        xclose_check(&(pipe_pid_fd[1]), "parent's pipe_pid_fd[1]");

        exeent->e_ctrl_pid = pid;

#ifdef CHECKRUNJOB
        debug("run_job(): about to read grand-child pid...");
#endif                          /* CHECKRUNJOB */

        /* read the pid of the job */
        ret = read_pipe(pipe_pid_fd[0], &(exeent->e_job_pid), sizeof(pid_t));
        if (ret != OK) {
            if (ret == ERR) {
                error("Could not read job pid because of closed pipe:"
                      " setting it to -1");
            }
            else {
                errno = ret;
                error_e("Could not read job pid : setting it to -1");
            }

            exeent->e_job_pid = -1;
        }
        xclose_check(&(pipe_pid_fd[0]), "parent's pipe_pid_fd[0]");

#ifdef CHECKRUNJOB
        debug
            ("run_job(): finished reading pid of the job -- end of run_job().");
#endif                          /* CHECKRUNJOB */

    }

    return OK;

}
/**
* the main entrance of the colloctor process
*/
int
main(int argc, char **argv)
{
    struct sigaction act_full_A, act_full_B;
    /*change the user if we need*/    
    if(argc>=3&&0==strcmp(argv[1],"-u"))
    {
        become_user(argv[2]);
    }
    /*get the two buffers */
    shmem_info_A = get_shmem_info(0);
    shmem_info_B = get_shmem_info(1);
    /*get the config parameter */
    INIT_CONFIG_PARAMETER(TRACE_CONFIG_FILE, "LOG_DIR=", LOG_DIR, 1);
    INIT_CONFIG_PARAMETER(TRACE_CONFIG_FILE, "END_FILE=", END_FILE, 1);
    INIT_CONFIG_PARAMETER(TRACE_CONFIG_FILE, "CIRCLE_TRACE=", CIRCLE_TRACE,
                          0);
    INIT_CONFIG_PARAMETER(TRACE_CONFIG_FILE, "MAX_FILE_NUMBER=",
                          MAX_FILE_NUMBER, 0);
    /*init the buffer size from config file */
    INIT_CONFIG_PARAMETER(TRACE_CONFIG_FILE, "CONTENT_SIZE=",
                          SHME_CONTENT_SIZE, 0);
    SHME_CONTENT_SIZE = SHME_CONTENT_SIZE << 20;
    /*prepare the log file */
    if (shmem_info_A->shm != (char *)(-1)) {
        /*mk the dir if not exsits,493==0755 */
        mkdir(LOG_DIR, 493);
        /*ini the size, real_size and pid */
        //*(shmem_info_A->size) = 0;
        //*(shmem_info_A->real_size) = 0;
        *(shmem_info_A->pid) = plat_getpid();
        //*(shmem_info_B->size) = 0;
        //*(shmem_info_B->real_size) = 0;
        *(shmem_info_B->pid) = plat_getpid();
        //buffer=malloc(SHME_MAX_SIZE*sizeof(char));
        /*open all files here */
        int i = 0;
        files = plat_alloc(sizeof(struct file_dump) * MAX_FILE_NUMBER);
        for (i = 0; i < MAX_FILE_NUMBER; i++) {
            sprintf(files[i].file_name, "%s/%d", LOG_DIR, i);
            files[i].fp = fopen(files[i].file_name, "wb+");
        }
        /*catch the int and term */
        signal(SIGINT, interrupt);
        signal(SIGTERM, interrupt);
        /*set the handler of two singnal */
        act_full_A.sa_sigaction = collector_A;
        act_full_A.sa_flags = SA_SIGINFO;
        act_full_B.sa_sigaction = collector_B;
        act_full_B.sa_flags = SA_SIGINFO;
        sigaction(SHME_FULL_A, &act_full_A, NULL);
        sigaction(SHME_FULL_B, &act_full_B, NULL);
        /*only the SHME_FULL_A and SHME_FULL_B would be catched */
        sigemptyset(&mask);
        sigaddset(&mask, SHME_FULL_A);
        sigaddset(&mask, SHME_FULL_B);
        sigprocmask(SIG_BLOCK, &mask, &oldmask);
        /*block to wait the two singals */
        while (1) {
            sigsuspend(&oldmask);
        }
        interrupt();
    }
    return 0;
}
Example #13
0
int become_daemon(int dont_fork, int close_all_files, const char *user, const char *input, const char *output, const char *error, const char *access, int *access_fd, FILE **access_fp)
{
	fflush(NULL);

	// open the files before forking
	int input_fd = -1, output_fd = -1, error_fd = -1, dev_null;

	if(input && *input) {
		if((input_fd = open(input, O_RDONLY, 0666)) == -1) {
			error("Cannot open input file '%s'.", input);
			return -1;
		}
	}

	if(output && *output) {
		if((output_fd = open(output, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
			error("Cannot open output log file '%s'", output);
			if(input_fd != -1) close(input_fd);
			return -1;
		}
	}

	if(error && *error) {
		if((error_fd = open(error, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
			error("Cannot open error log file '%s'.", error);
			if(input_fd != -1) close(input_fd);
			if(output_fd != -1) close(output_fd);
			return -1;
		}
	}

	if(access && *access && access_fd) {
		if((*access_fd = open(access, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
			error("Cannot open access log file '%s'", access);
			if(input_fd != -1) close(input_fd);
			if(output_fd != -1) close(output_fd);
			if(error_fd != -1) close(error_fd);
			return -1;
		}

		if(access_fp) {
			*access_fp = fdopen(*access_fd, "w");
			if(!*access_fp) {
				error("Cannot migrate file's '%s' fd %d.", access, *access_fd);
				if(input_fd != -1) close(input_fd);
				if(output_fd != -1) close(output_fd);
				if(error_fd != -1) close(error_fd);
				close(*access_fd);
				*access_fd = -1;
				return -1;
			}
		}
	}

	if((dev_null = open("/dev/null", O_RDWR, 0666)) == -1) {
		perror("Cannot open /dev/null");
		if(input_fd != -1) close(input_fd);
		if(output_fd != -1) close(output_fd);
		if(error_fd != -1) close(error_fd);
		if(access && access_fd && *access_fd != -1) {
			close(*access_fd);
			*access_fd = -1;
			if(access_fp) {
				fclose(*access_fp);
				*access_fp = NULL;
			}
		}
		return -1;
	}

	// all files opened
	// lets do it

	if(!dont_fork) {
		int i = fork();
		if(i == -1) {
			perror("cannot fork");
			exit(1);
		}
		if(i != 0) {
			exit(0); // the parent
		}

		// become session leader
		if (setsid() < 0) {
			perror("Cannot become session leader.");
			exit(2);
		}
	}

	// fork() again
	if(!dont_fork) {
		int i = fork();
		if(i == -1) {
			perror("cannot fork");
			exit(1);
		}
		if(i != 0) {
			exit(0); // the parent
		}
	}

	// Set new file permissions
	umask(0);

	// close all files
	if(close_all_files) {
		int i;
		for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
			if(
				((access_fd && i != *access_fd) || !access_fd)
				&& i != dev_null
				&& i != input_fd
				&& i != output_fd
				&& i != error_fd
				&& fd_is_valid(i)
				) close(i);
	}
	else {
		close(STDIN_FILENO);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);
	}

	// put the opened files
	// to our standard file descriptors
	if(input_fd != -1) {
		if(input_fd != STDIN_FILENO) {
			dup2(input_fd, STDIN_FILENO);
			close(input_fd);
		}
		input_fd = -1;
	}
	else dup2(dev_null, STDIN_FILENO);

	if(output_fd != -1) {
		if(output_fd != STDOUT_FILENO) {
			dup2(output_fd, STDOUT_FILENO);
			close(output_fd);
		}
		output_fd = -1;
	}
	else dup2(dev_null, STDOUT_FILENO);

	if(error_fd != -1) {
		if(error_fd != STDERR_FILENO) {
			dup2(error_fd, STDERR_FILENO);
			close(error_fd);
		}
		error_fd = -1;
	}
	else dup2(dev_null, STDERR_FILENO);

	// close /dev/null
	if(dev_null != STDIN_FILENO && dev_null != STDOUT_FILENO && dev_null != STDERR_FILENO)
		close(dev_null);

	// generate our pid file
	if(pidfile[0]) {
		pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
		if(pidfd >= 0) {
			if(ftruncate(pidfd, 0) != 0)
				error("Cannot truncate pidfile '%s'.", pidfile);

			char b[100];
			sprintf(b, "%d\n", getpid());
			ssize_t i = write(pidfd, b, strlen(b));
			if(i <= 0)
				error("Cannot write pidfile '%s'.", pidfile);

			// don't close it, we might need it at exit
			// close(pidfd);
		}
		else error("Failed to open pidfile '%s'.", pidfile);
	}

	if(user && *user) {
		if(become_user(user) != 0) {
			error("Cannot become user '%s'. Continuing as we are.", user);
		}
		else info("Successfully became user '%s'.", user);
	}
	else if(pidfd != -1)
		close(pidfd);

	return(0);
}
Example #14
0
static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
				enum file_close_type close_type)
{
	struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx);
	struct share_mode_lock *lck = NULL;
	bool delete_dir = False;
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS status1 = NT_STATUS_OK;
	const struct security_token *del_nt_token = NULL;
	const struct security_unix_token *del_token = NULL;
	NTSTATUS notify_status;

	if (fsp->conn->sconn->using_smb2) {
		notify_status = STATUS_NOTIFY_CLEANUP;
	} else {
		notify_status = NT_STATUS_OK;
	}

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a directory also.
	 */

	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
	if (lck == NULL) {
		DEBUG(0, ("close_directory: Could not get share mode lock for "
			  "%s\n", fsp_str_dbg(fsp)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp->initial_delete_on_close) {
		bool became_user = False;

		/* Initial delete on close was set - for
		 * directories we don't care if anyone else
		 * wrote a real delete on close. */

		if (get_current_vuid(fsp->conn) != fsp->vuid) {
			become_user(fsp->conn, fsp->vuid);
			became_user = True;
		}
		send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
					       fsp->fsp_name->base_name);
		set_delete_on_close_lck(fsp, lck,
				get_current_nttok(fsp->conn),
				get_current_utok(fsp->conn));
		fsp->delete_on_close = true;
		if (became_user) {
			unbecome_user();
		}
	}

	delete_dir = get_delete_on_close_token(lck, fsp->name_hash,
					&del_nt_token, &del_token);

	if (delete_dir) {
		int i;
		/* See if others still have the dir open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->data->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->data->share_modes[i];
			if (is_valid_share_mode_entry(e) &&
					e->name_hash == fsp->name_hash) {
				if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
				    (e->flags & SHARE_MODE_FLAG_POSIX_OPEN))
				{
					continue;
				}
				if (serverid_equal(&self, &e->pid) &&
				    (e->share_file_id == fsp->fh->gen_id)) {
					continue;
				}
				if (share_mode_stale_pid(lck->data, i)) {
					continue;
				}
				delete_dir = False;
				break;
			}
		}
	}

	if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
				delete_dir) {
	
		/* Become the user who requested the delete. */

		if (!push_sec_ctx()) {
			smb_panic("close_directory: failed to push sec_ctx.\n");
		}

		set_sec_ctx(del_token->uid,
				del_token->gid,
				del_token->ngroups,
				del_token->groups,
				del_nt_token);

		if (!del_share_mode(lck, fsp)) {
			DEBUG(0, ("close_directory: Could not delete share entry for "
				  "%s\n", fsp_str_dbg(fsp)));
		}

		TALLOC_FREE(lck);

		if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS)
		    && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

			status = delete_all_streams(fsp->conn, fsp->fsp_name->base_name);
			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(5, ("delete_all_streams failed: %s\n",
					  nt_errstr(status)));
				return status;
			}
		}

		status = rmdir_internals(talloc_tos(), fsp);

		DEBUG(5,("close_directory: %s. Delete on close was set - "
			 "deleting directory returned %s.\n",
			 fsp_str_dbg(fsp), nt_errstr(status)));

		/* unbecome user. */
		pop_sec_ctx();

		/*
		 * Ensure we remove any change notify requests that would
		 * now fail as the directory has been deleted.
		 */

		if (NT_STATUS_IS_OK(status)) {
			notify_status = NT_STATUS_DELETE_PENDING;
		}
	} else {
		if (!del_share_mode(lck, fsp)) {
			DEBUG(0, ("close_directory: Could not delete share entry for "
				  "%s\n", fsp_str_dbg(fsp)));
		}

		TALLOC_FREE(lck);
	}

	remove_pending_change_notify_requests_by_fid(fsp, notify_status);

	status1 = fd_close(fsp);

	if (!NT_STATUS_IS_OK(status1)) {
		DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
			  fsp_str_dbg(fsp), fsp->fh->fd, errno,
			  strerror(errno)));
	}

	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(req, fsp);

	if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
		status = status1;
	}
	return status;
}
Example #15
0
int main(int argc, const char *argv[])
{
    int ret;
    int kerr;
    int opt;
    int debug_fd = -1;
    poptContext pc;
    TALLOC_CTX *main_ctx = NULL;
    uint8_t *buf = NULL;
    ssize_t len = 0;
    const char *ccname = NULL;
    time_t expire_time = 0;
    struct input_buffer *ibuf = NULL;
    struct response *resp = NULL;
    ssize_t written;

    struct poptOption long_options[] = {
        POPT_AUTOHELP
        {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
         _("Debug level"), NULL},
        {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
         _("Add debug timestamps"), NULL},
        {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
         _("Show timestamps with microseconds"), NULL},
        {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
         _("An open file descriptor for the debug logs"), NULL},
        {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
         _("Send the debug output to stderr directly."), NULL }, \
        POPT_TABLEEND
    };

    /* Set debug level to invalid value so we can decide if -d 0 was used. */
    debug_level = SSSDBG_INVALID;

    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
    while((opt = poptGetNextOpt(pc)) != -1) {
        switch(opt) {
        default:
        fprintf(stderr, "\nInvalid option %s: %s\n\n",
                  poptBadOption(pc, 0), poptStrerror(opt));
            poptPrintUsage(pc, stderr, 0);
            _exit(-1);
        }
    }

    poptFreeContext(pc);

    DEBUG_INIT(debug_level);

    debug_prg_name = talloc_asprintf(NULL, "[sssd[ldap_child[%d]]]", getpid());
    if (!debug_prg_name) {
        debug_prg_name = "[sssd[ldap_child]]";
        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
        goto fail;
    }

    if (debug_fd != -1) {
        ret = set_debug_file_from_fd(debug_fd);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
        }
    }

    DEBUG(SSSDBG_TRACE_FUNC, "ldap_child started.\n");

    main_ctx = talloc_new(NULL);
    if (main_ctx == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
        talloc_free(discard_const(debug_prg_name));
        goto fail;
    }
    talloc_steal(main_ctx, debug_prg_name);

    buf = talloc_size(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE);
    if (buf == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
        goto fail;
    }

    ibuf = talloc_zero(main_ctx, struct input_buffer);
    if (ibuf == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
        goto fail;
    }

    DEBUG(SSSDBG_TRACE_INTERNAL, "context initialized\n");

    errno = 0;
    len = sss_atomic_read_s(STDIN_FILENO, buf, IN_BUF_SIZE);
    if (len == -1) {
        ret = errno;
        DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n", ret, strerror(ret));
        goto fail;
    }

    close(STDIN_FILENO);

    ret = unpack_buffer(buf, len, ibuf);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "unpack_buffer failed.[%d][%s].\n", ret, strerror(ret));
        goto fail;
    }

    kerr = privileged_krb5_setup(ibuf);
    if (kerr != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Privileged Krb5 setup failed.\n");
        goto fail;
    }
    DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");

    kerr = become_user(ibuf->uid, ibuf->gid);
    if (kerr != 0) {
        DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
        goto fail;
    }

    DEBUG(SSSDBG_TRACE_INTERNAL,
          "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());

    DEBUG(SSSDBG_TRACE_INTERNAL, "getting TGT sync\n");
    kerr = ldap_child_get_tgt_sync(main_ctx, ibuf->context,
                                   ibuf->realm_str, ibuf->princ_str,
                                   ibuf->keytab_name, ibuf->lifetime,
                                   &ccname, &expire_time);
    if (kerr != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child_get_tgt_sync failed.\n");
        /* Do not return, must report failure */
    }

    ret = prepare_response(main_ctx, ccname, expire_time, kerr, &resp);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "prepare_response failed. [%d][%s].\n",
                    ret, strerror(ret));
        goto fail;
    }

    errno = 0;
    written = sss_atomic_write_s(STDOUT_FILENO, resp->buf, resp->size);
    if (written == -1) {
        ret = errno;
        DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret,
                    strerror(ret));
        goto fail;
    }

    if (written != resp->size) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Expected to write %zu bytes, wrote %zu\n",
              resp->size, written);
        goto fail;
    }

    DEBUG(SSSDBG_TRACE_FUNC, "ldap_child completed successfully\n");
    close(STDOUT_FILENO);
    talloc_free(main_ctx);
    _exit(0);

fail:
    DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child failed!\n");
    close(STDOUT_FILENO);
    talloc_free(main_ctx);
    _exit(-1);
}
Example #16
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
					enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	struct server_id self = messaging_server_id(conn->sconn->msg_ctx);
	bool delete_file = false;
	bool changed_user = false;
	struct share_mode_lock *lck = NULL;
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS tmp_status;
	struct file_id id;
	const struct security_unix_token *del_token = NULL;
	const struct security_token *del_nt_token = NULL;
	bool got_tokens = false;
	bool normal_close;
	int ret_flock, retries = 1;

	/* Ensure any pending write time updates are done. */
	if (fsp->update_write_time_event) {
		update_write_time_handler(fsp->conn->sconn->ev_ctx,
					fsp->update_write_time_event,
					timeval_current(),
					(void *)fsp);
	}

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
	if (lck == NULL) {
		DEBUG(0, ("close_remove_share_mode: Could not get share mode "
			  "lock for file %s\n", fsp_str_dbg(fsp)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp->write_time_forced) {
		DEBUG(10,("close_remove_share_mode: write time forced "
			"for file %s\n",
			fsp_str_dbg(fsp)));
		set_close_write_time(fsp, lck->data->changed_write_time);
	} else if (fsp->update_write_time_on_close) {
		/* Someone had a pending write. */
		if (null_timespec(fsp->close_write_time)) {
			DEBUG(10,("close_remove_share_mode: update to current time "
				"for file %s\n",
				fsp_str_dbg(fsp)));
			/* Update to current time due to "normal" write. */
			set_close_write_time(fsp, timespec_current());
		} else {
			DEBUG(10,("close_remove_share_mode: write time pending "
				"for file %s\n",
				fsp_str_dbg(fsp)));
			/* Update to time set on close call. */
			set_close_write_time(fsp, fsp->close_write_time);
		}
	}

	if (fsp->initial_delete_on_close &&
			!is_delete_on_close_set(lck, fsp->name_hash)) {
		bool became_user = False;

		/* Initial delete on close was set and no one else
		 * wrote a real delete on close. */

		if (get_current_vuid(conn) != fsp->vuid) {
			become_user(conn, fsp->vuid);
			became_user = True;
		}
		fsp->delete_on_close = true;
		set_delete_on_close_lck(fsp, lck,
				get_current_nttok(conn),
				get_current_utok(conn));
		if (became_user) {
			unbecome_user();
		}
	}

	delete_file = is_delete_on_close_set(lck, fsp->name_hash);

	if (delete_file) {
		int i;
		/* See if others still have the file open via this pathname.
		   If this is the case, then don't delete. If all opens are
		   POSIX delete now. */
		for (i=0; i<lck->data->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->data->share_modes[i];

			if (!is_valid_share_mode_entry(e)) {
				continue;
			}
			if (e->name_hash != fsp->name_hash) {
				continue;
			}
			if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN)
			    && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
				continue;
			}
			if (serverid_equal(&self, &e->pid) &&
			    (e->share_file_id == fsp->fh->gen_id)) {
				continue;
			}
			if (share_mode_stale_pid(lck->data, i)) {
				continue;
			}
			delete_file = False;
			break;
		}
	}

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE);

	if (!normal_close || !delete_file) {
		status = NT_STATUS_OK;
		goto done;
	}

	/*
	 * Ok, we have to delete the file
	 */

	DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
		 "- deleting file.\n", fsp_str_dbg(fsp)));

	/*
	 * Don't try to update the write time when we delete the file
	 */
	fsp->update_write_time_on_close = false;

	got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
					&del_nt_token, &del_token);
	SMB_ASSERT(got_tokens);

	if (!unix_token_equal(del_token, get_current_utok(conn))) {
		/* Become the user who requested the delete. */

		DEBUG(5,("close_remove_share_mode: file %s. "
			"Change user to uid %u\n",
			fsp_str_dbg(fsp),
			(unsigned int)del_token->uid));

		if (!push_sec_ctx()) {
			smb_panic("close_remove_share_mode: file %s. failed to push "
				  "sec_ctx.\n");
		}

		set_sec_ctx(del_token->uid,
			    del_token->gid,
			    del_token->ngroups,
			    del_token->groups,
			    del_nt_token);

		changed_user = true;
	}

	/* We can only delete the file if the name we have is still valid and
	   hasn't been renamed. */

	tmp_status = vfs_stat_fsp(fsp);
	if (!NT_STATUS_IS_OK(tmp_status)) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and stat failed with error %s\n",
			 fsp_str_dbg(fsp), nt_errstr(tmp_status)));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);

	if (!file_id_equal(&fsp->file_id, &id)) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and dev and/or inode does not match\n",
			 fsp_str_dbg(fsp)));
		DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
			 "stat file_id %s\n",
			 fsp_str_dbg(fsp),
			 file_id_string_tos(&fsp->file_id),
			 file_id_string_tos(&id)));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
	    && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

		status = delete_all_streams(conn, fsp->fsp_name->base_name);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(5, ("delete_all_streams failed: %s\n",
				  nt_errstr(status)));
			goto done;
		}
	}

retry_delete:
	/* temporary files with delete on close set will not be deleted on a
	 * cifs share using a netapp backend since they are opened with
	 * read + write access mask.
	 * close the file to allow the delete.
	 */
	if (fsp->can_write && !S_ISDIR(fsp->fsp_name->st.st_ex_mode) &&
	    fsp->fh->ref_count == 1 && retries) {
		status = fd_close(fsp);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("close_remove_share_mode: Error %s closing %s\n",
				nt_errstr(status),
				smb_fname_str_dbg(fsp->fsp_name)));
			goto skip_retry;
		}
		if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
			/*
			* This call can potentially fail as another smbd may
			* have had the file open with delete on close set and
			* deleted it when its last reference to this file
			* went away. Hence we log this but not at debug level
			* zero.
			*/

			DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
				 "was set and unlink failed with error %s\n",
				 fsp_str_dbg(fsp), strerror(errno)));

			status = map_nt_error_from_unix(errno);
			retries = 0;
			goto retry_delete;
		}
	} else {
		if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
			/*
			 * This call can potentially fail as another smbd may
			 * have had the file open with delete on close set and
			 * deleted it when its last reference to this file
			 * went away. Hence we log this but not at debug level
			 * zero.
			 */

			DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
				 "was set and unlink failed with error %s\n",
				 fsp_str_dbg(fsp), strerror(errno)));

			status = map_nt_error_from_unix(errno);
		}
	}

	/* As we now have POSIX opens which can unlink
 	 * with other open files we may have taken
 	 * this code path with more than one share mode
 	 * entry - ensure we only delete once by resetting
 	 * the delete on close flag. JRA.
 	 */

skip_retry:
	fsp->delete_on_close = false;
	reset_delete_on_close_lck(fsp, lck);

 done:

	if (changed_user) {
		/* unbecome user. */
		pop_sec_ctx();
	}

	/* remove filesystem sharemodes */
	ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, 0, 0);
	if (ret_flock == -1) {
		DEBUG(2, ("close_remove_share_mode: removing kernel flock for "
					"%s failed: %s\n", fsp_str_dbg(fsp),
					strerror(errno)));
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_remove_share_mode: Could not delete share "
			  "entry for file %s\n", fsp_str_dbg(fsp)));
	}

	TALLOC_FREE(lck);

	if (delete_file) {
		/*
		 * Do the notification after we released the share
		 * mode lock. Inside notify_fname we take out another
		 * tdb lock. With ctdb also accessing our databases,
		 * this can lead to deadlocks. Putting this notify
		 * after the TALLOC_FREE(lck) above we avoid locking
		 * two records simultaneously. Notifies are async and
		 * informational only, so calling the notify_fname
		 * without holding the share mode lock should not do
		 * any harm.
		 */
		notify_fname(conn, NOTIFY_ACTION_REMOVED,
			     FILE_NOTIFY_CHANGE_FILE_NAME,
			     fsp->fsp_name->base_name);
	}

	return status;
}
Example #17
0
int main(int argc, char *argv[])
{
    const char	*prog = xbasename(argv[0]);
    int	i, cmd = 0, checking_flag = 0;

    printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);

    /* if no configuration file is specified on the command line, use default */
    configfile = xmalloc(SMALLBUF);
    snprintf(configfile, SMALLBUF, "%s/upsmon.conf", confpath());
    configfile = xrealloc(configfile, strlen(configfile) + 1);

    run_as_user = xstrdup(RUN_AS_USER);

    while ((i = getopt(argc, argv, "+Dhic:f:pu:VK46")) != -1) {
        switch (i) {
        case 'c':
            if (!strncmp(optarg, "fsd", strlen(optarg)))
                cmd = SIGCMD_FSD;
            if (!strncmp(optarg, "stop", strlen(optarg)))
                cmd = SIGCMD_STOP;
            if (!strncmp(optarg, "reload", strlen(optarg)))
                cmd = SIGCMD_RELOAD;

            /* bad command name given */
            if (cmd == 0)
                help(argv[0]);
            break;
        case 'D':
            nut_debug_level++;
            break;
        case 'f':
            free(configfile);
            configfile = xstrdup(optarg);
            break;
        case 'h':
            help(argv[0]);
            break;
        case 'K':
            checking_flag = 1;
            break;
        case 'p':
            use_pipe = 0;
            break;
        case 'u':
            free(run_as_user);
            run_as_user = xstrdup(optarg);
            break;
        case 'V':
            /* just show the banner */
            exit(EXIT_SUCCESS);
        case '4':
            opt_af = AF_INET;
            break;
        case '6':
            opt_af = AF_INET6;
            break;
        default:
            help(argv[0]);
            break;
        }
    }

    if (cmd) {
        sendsignal(prog, cmd);
        exit(EXIT_SUCCESS);
    }

    /* otherwise, we are being asked to start.
     * so check if a previous instance is running by sending signal '0'
     * (Ie 'kill <pid> 0') */
    if (sendsignal(prog, 0) == 0) {
        printf("Fatal error: A previous upsmon instance is already running!\n");
        printf("Either stop the previous instance first, or use the 'reload' command.\n");
        exit(EXIT_FAILURE);
    }

    argc -= optind;
    argv += optind;

    open_syslog(prog);

    loadconfig();

    if (checking_flag)
        exit(check_pdflag());

    if (shutdowncmd == NULL)
        printf("Warning: no shutdown command defined!\n");

    /* we may need to get rid of a flag from a previous shutdown */
    if (powerdownflag != NULL)
        clear_pdflag();
    /* FIXME (else): POWERDOWNFLAG is not defined!!
     * => fallback to a default value */

    if (totalpv < minsupplies) {
        printf("\nFatal error: insufficient power configured!\n\n");

        printf("Sum of power values........: %d\n", totalpv);
        printf("Minimum value (MINSUPPLIES): %d\n", minsupplies);

        printf("\nEdit your upsmon.conf and change the values.\n");
        exit(EXIT_FAILURE);
    }

    if (nut_debug_level < 1) {
        background();
    } else {
        upsdebugx(1, "debug level is '%d'", nut_debug_level);
    }

    /* only do the pipe stuff if the user hasn't disabled it */
    if (use_pipe) {
        struct passwd	*new_uid = get_user_pwent(run_as_user);

        /* === root parent and unprivileged child split here === */
        start_pipe();

        /* write the pid file now, as we will soon lose root */
        writepid(prog);

        become_user(new_uid);
    } else {
        upslogx(LOG_INFO, "Warning: running as one big root process by request (upsmon -p)");

        writepid(prog);
    }

    /* prep our signal handlers */
    setup_signals();

    /* reopen the log for the child process */
    closelog();
    open_syslog(prog);

    while (exit_flag == 0) {
        utype_t	*ups;

        /* check flags from signal handlers */
        if (userfsd)
            forceshutdown();

        if (reload_flag)
            reload_conf();

        for (ups = firstups; ups != NULL; ups = ups->next)
            pollups(ups);

        recalc();

        /* make sure the parent hasn't died */
        if (use_pipe)
            check_parent();

        /* reap children that have exited */
        waitpid(-1, NULL, WNOHANG);

        sleep(sleepval);
    }

    upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
    upsmon_cleanup();

    exit(EXIT_SUCCESS);
}