예제 #1
0
파일: my_cd.c 프로젝트: k0ink0in/42sh
int		my_cd(char *str, t_struct *pile)
{
  struct stat	s;
  int		n;
  char		*tmp;

  n = 0;
  tmp = NULL;
  if ((str != NULL) && (*str == 0))
    str = my_aff_param_list(pile->my_env, HOME);
  if (str == NULL)
    str = my_strdup(pile->home);
  if ((str != NULL) && (str[0] != '/') && (str[0] != '-') && str[0] != '.')
    tmp = my_strcat("./", str);
  else if (str != NULL)
    tmp = my_strdup(str);
  if ((str != NULL) && (str[0] != '-') && (stat(tmp, &s) < 0))
    {
      msg_error(str, NO_FILE_DIR, pile);
      return (0);
    }
  if ((str != NULL) && ((str[0] == '-') || (check_perm(s, tmp) == 0)))
    find_cd(tmp, pile);
  else
    msg_error(str, ": Permission denied\n", pile);
  cd_check(tmp);
  return (0);
}
예제 #2
0
파일: validate.c 프로젝트: KISSMonX/monit
/**
 * Validate a given file service s. Events are posted according to 
 * its configuration. In case of a fatal event FALSE is returned.
 */
int check_file(Service_T s) {
  struct stat stat_buf;

  ASSERT(s);

  if (stat(s->path, &stat_buf) != 0) {
    Event_post(s, Event_Nonexist, STATE_FAILED, s->action_NONEXIST, "file doesn't exist");
    return FALSE;
  } else {
    s->inf->st_mode = stat_buf.st_mode;
    if (s->inf->priv.file.st_ino == 0) {
      s->inf->priv.file.st_ino_prev = stat_buf.st_ino;
      s->inf->priv.file.readpos     = stat_buf.st_size;
    } else
      s->inf->priv.file.st_ino_prev = s->inf->priv.file.st_ino;
    s->inf->priv.file.st_ino  = stat_buf.st_ino;
    s->inf->st_uid            = stat_buf.st_uid;
    s->inf->st_gid            = stat_buf.st_gid;
    s->inf->priv.file.st_size = stat_buf.st_size;
    s->inf->timestamp         = MAX(stat_buf.st_mtime, stat_buf.st_ctime);
    DEBUG("'%s' file exists check succeeded\n", s->name);
    Event_post(s, Event_Nonexist, STATE_SUCCEEDED, s->action_NONEXIST, "file exist");
  }

  if (!S_ISREG(s->inf->st_mode)) {
    Event_post(s, Event_Invalid, STATE_FAILED, s->action_INVALID, "is not a regular file");
    return FALSE;
  } else {
    DEBUG("'%s' is a regular file\n", s->name);
    Event_post(s, Event_Invalid, STATE_SUCCEEDED, s->action_INVALID, "is a regular file");
  }

  if (s->checksum)
    check_checksum(s);

  if (s->perm)
    check_perm(s);

  if (s->uid)
    check_uid(s);

  if (s->gid)
    check_gid(s);

  if (s->sizelist)
    check_size(s);

  if (s->timestamplist)
    check_timestamp(s);

  if (s->matchlist)
    check_match(s);

  return TRUE;

}
예제 #3
0
파일: jail.c 프로젝트: guoyu07/jff
int creat64(const char *pathname, mode_t mode)
{
    DBG("pathname=%s, mode=%d\n", pathname, mode);

    if (check_perm(pathname, RESTRICTED_ALLOW_OPEN_WRITE_ENV,
                   &patterns_open_write))
        return -1;

    return real_creat64(pathname, mode);
}
예제 #4
0
파일: jail.c 프로젝트: guoyu07/jff
DIR* opendir(const char* pathname)
{
    DBG("pathname=%s\n", pathname);

    if (check_perm(pathname, RESTRICTED_ALLOW_OPENDIR_ENV,
                   &patterns_opendir))
        return NULL;

    return real_opendir(pathname);
}
예제 #5
0
파일: jail.c 프로젝트: guoyu07/jff
int rmdir(const char *pathname)
{
    DBG("pathname=%s\n", pathname);

    if (check_perm(pathname, RESTRICTED_ALLOW_RMDIR_ENV,
                   &patterns_rmdir))
        return -1;

    return real_rmdir(pathname);
}
예제 #6
0
파일: jail.c 프로젝트: guoyu07/jff
int mkdir(const char *pathname, mode_t mode)
{
    DBG("pathname=%s, mode=%d\n", pathname, mode);

    if (check_perm(pathname, RESTRICTED_ALLOW_MKDIR_ENV,
                   &patterns_mkdir))
        return -1;

    return real_mkdir(pathname, mode);
}
예제 #7
0
파일: jail.c 프로젝트: guoyu07/jff
int execve(const char *filename,
           char *const argv[], char *const envp[])
{
    DBG("filename=%s\n", filename);

    if (check_perm(filename, RESTRICTED_ALLOW_EXEC_ENV,
                   &patterns_execve))
        return -1;

    return real_execve(filename, argv, envp);
}
예제 #8
0
파일: validate.c 프로젝트: bumper-app/nicad
/**
 * Validate a given directory service s.  Events are posted according to 
 * its configuration.  In case of a fatal event FALSE is returned.
 */
int check_directory(Service_T s) {

  struct stat stat_buf;
  char report[STRLEN]= {0};

  if(stat(s->path, &stat_buf) != 0) {
    if(! s->event_handled) {
      Event_post(s, EVENT_START,
		 "Event: directory '%s' doesn't exist\n", s->name);
      s->event_handled= TRUE;
    }
    return FALSE;
  } else {
    s->event_handled= FALSE;
  }

  if(!S_ISDIR(stat_buf.st_mode)) {
    if(!s->event_handled) {
      Event_post(s, EVENT_UNMONITOR,
		 "Event: '%s' is not directory\n", s->name);
      s->event_handled= TRUE;
    }
    return FALSE;
  } else {
    s->event_handled= FALSE;
  }
  
  if(check_perm(s, stat_buf.st_mode, report)) {
    s->perm->event_flag= TRUE;
    if(! eval_actions(s->perm->action, s, report, "permission",
		      EVENT_PERMISSION))
	return FALSE;
  }
  
  if(check_uid(s, stat_buf.st_uid, report)) {
    s->uid->event_flag= TRUE;
    if(! eval_actions(s->uid->action, s, report, "uid", EVENT_UID))
	return FALSE;
  } 
  
  if(check_gid(s, stat_buf.st_gid, report)) {
    s->gid->event_flag= TRUE;
    if(! eval_actions(s->gid->action, s, report, "gid", EVENT_GID))
	return FALSE;
  } 

  if(!check_timestamps(s))
    return FALSE;

  return TRUE;

}
예제 #9
0
파일: sem.c 프로젝트: DragonQuan/minix3
/*===========================================================================*
 *				do_semget		     		     *
 *===========================================================================*/
PUBLIC int do_semget(message *m)
{
	key_t key;
	int nsems, flag, id;
	struct sem_struct *sem;

	key = m->SEMGET_KEY;
	nsems = m->SEMGET_NR;
	flag = m->SEMGET_FLAG;

	if ((sem = sem_find_key(key))) {
		if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
			return EEXIST;
		if (!check_perm(&sem->semid_ds.sem_perm, who_e, flag))
			return EACCES;
		if (nsems > sem->semid_ds.sem_nsems)
			return EINVAL;
		id = sem->id;
	} else {
		if (!(flag & IPC_CREAT))
			return ENOENT;
		if (nsems < 0 || nsems >= SEMMSL)
			return EINVAL;
		if (sem_list_nr == SEMMNI)
			return ENOSPC;

		/* create a new semaphore set */
		sem = &sem_list[sem_list_nr];
		memset(sem, 0, sizeof(struct sem_struct));
		sem->semid_ds.sem_perm.cuid =
			sem->semid_ds.sem_perm.uid = getnuid(who_e);
		sem->semid_ds.sem_perm.cgid =
			sem->semid_ds.sem_perm.gid = getngid(who_e);
		sem->semid_ds.sem_perm.mode = flag & 0777;
		sem->semid_ds.sem_nsems = nsems;
		sem->semid_ds.sem_otime = 0;
		sem->semid_ds.sem_ctime = time(NULL);
		sem->id = id = identifier++;
		sem->key = key;

		sem_list_nr++;
	}

	m->SEMGET_RETID = id;
	return OK;
}
예제 #10
0
파일: su.c 프로젝트: koneu/-Super
int
main(int argc, char *argv[]) {
	int user_new = 0;
	char *command = NULL, *shell = getenv("SHELL");
	ARGBEGIN {
	case 'l':
	case 'f':
	case 'm':
	case 'p':
		break;
	case 's':
		shell = EARGF(usage());
		break;
    case 'c':
		command = EARGF(usage());
		break;
	case 'v':
		puts("µSU v0.45");
	default:
		usage();
		break;
	} ARGEND;
	if(argc > 0) {
		user_new = atoi(argv[0]);
		argc--;
	}
	if(argc > 0) {
		usage();
	}
	if(check_perm()) {
		if(!shell) {
			shell = "sh";
		}
		if(setuid(user_new)) {
			log("setuid(%i) failed", user_new);
			exit(EXIT_FAILURE);
		}
		setgid(user_new);
		if(command) {
			execlp(shell, "sh", "-c", command, NULL);
		}
		execlp(shell, "sh", "-", NULL);
	}
	exit(EXIT_FAILURE);
}
예제 #11
0
static int mount_fuse(const char *mnt, int flags)
{
    int res;
    int fd;
    const char *dev = FUSE_DEV;
    const char *type = "fuse";
    struct stat stbuf;

    res = check_perm(mnt, &stbuf);
    if(res == -1)
        return -1;

    fd = open(dev, O_RDWR);
    if(fd == -1) {
        int status;
        pid_t pid = fork();
        if(pid == 0) {
            setuid(0);
            execl("/sbin/modprobe", "/sbin/modprobe", "fuse", NULL);
            exit(1);
        }
        if(pid != -1)
            waitpid(pid, &status, 0);

        fd = open(dev, O_RDWR);
    }
    if(fd == -1) {
        fprintf(stderr, "%s: unable to open fuse device %s: %s\n", progname,
                dev, strerror(errno));
        return -1;
    }

    res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd, flags);
    if(res == -1)
        return -1;

    res = add_mount(dev, mnt, type);
    if(res == -1) {
        umount(mnt);
        return -1;
    }

    return fd;
}
예제 #12
0
static int mount_fuse(const char *mnt, const char *opts)
{
    int res;
    int fd;
    char *dev = NULL;
    struct stat stbuf;
    char *type = NULL;
    char *source = NULL;
    char *mnt_opts = NULL;
    const char *real_mnt = mnt;
    int currdir_fd = -1;
    int mountpoint_fd = -1;

    fd = open_fuse_device(&dev);
    if (fd == -1)
    {
        if(NULL != dev)
        {
            free(dev);
            dev = NULL;
        }
        return -1;
    }

    if (getuid() != 0 && mount_max != -1) {
        if (count_fuse_fs() >= mount_max) {
            fprintf(stderr, "%s: too many mounted FUSE filesystems (%d+)\n",
		    progname, mount_max);
	    goto err;
        }
    }

    res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
    if (res != -1)
         res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts, dev,
			&source, &mnt_opts);

    if (currdir_fd != -1) {
	 __attribute__((unused))int ignored_fchdir_status =
	        fchdir(currdir_fd);
        close(currdir_fd);
    }
예제 #13
0
파일: att.c 프로젝트: PchZhang/testgit
static uint8_t write_cb(const struct bt_gatt_attr *attr, void *user_data)
{
	struct write_data *data = user_data;
	int write;

	BT_DBG("handle 0x%04x", attr->handle);

	/* Check for write support and flush support in case of prepare */
	if (!attr->write ||
	    (data->op == BT_ATT_OP_PREPARE_WRITE_REQ && !attr->flush)) {
		data->err = BT_ATT_ERR_WRITE_NOT_PERMITTED;
		return BT_GATT_ITER_STOP;
	}

	/* Check attribute permissions */
	data->err = check_perm(data->conn, attr, BT_GATT_PERM_WRITE_MASK);
	if (data->err) {
		return BT_GATT_ITER_STOP;
	}

	/* Read attribute value and store in the buffer */
	write = attr->write(data->conn, attr, data->value, data->len,
			    data->offset);
	if (write < 0 || write != data->len) {
		data->err = err_to_att(write);
		return BT_GATT_ITER_STOP;
	}

	/* Flush in case of regular write operation */
	if (attr->flush && data->op != BT_ATT_OP_PREPARE_WRITE_REQ) {
		write = attr->flush(data->conn, attr, BT_GATT_FLUSH_SYNC);
		if (write < 0) {
			data->err = err_to_att(write);
			return BT_GATT_ITER_STOP;
		}
	}

	data->err = 0;

	return BT_GATT_ITER_CONTINUE;
}
예제 #14
0
파일: validate.c 프로젝트: KISSMonX/monit
/**
 * Validate a given fifo service s. Events are posted according to 
 * its configuration. In case of a fatal event FALSE is returned.
 */
int check_fifo(Service_T s) {

  struct stat stat_buf;

  ASSERT(s);

  if (stat(s->path, &stat_buf) != 0) {
    Event_post(s, Event_Nonexist, STATE_FAILED, s->action_NONEXIST, "fifo doesn't exist");
    return FALSE;
  } else {
    s->inf->st_mode   = stat_buf.st_mode;
    s->inf->st_uid    = stat_buf.st_uid;
    s->inf->st_gid    = stat_buf.st_gid;
    s->inf->timestamp = MAX(stat_buf.st_mtime, stat_buf.st_ctime);
    DEBUG("'%s' fifo exists check succeeded\n", s->name);
    Event_post(s, Event_Nonexist, STATE_SUCCEEDED, s->action_NONEXIST, "fifo exist");
  }

  if (!S_ISFIFO(s->inf->st_mode)) {
    Event_post(s, Event_Invalid, STATE_FAILED, s->action_INVALID, "is not fifo");
    return FALSE;
  } else {
    DEBUG("'%s' is fifo\n", s->name);
    Event_post(s, Event_Invalid, STATE_SUCCEEDED, s->action_INVALID, "is fifo");
  }

  if (s->perm)
    check_perm(s);

  if (s->uid)
    check_uid(s);

  if (s->gid)
    check_gid(s);

  if (s->timestamplist)
    check_timestamp(s);

  return TRUE;

}
예제 #15
0
파일: att.c 프로젝트: PchZhang/testgit
static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
{
	struct read_data *data = user_data;
	struct bt_att *att = data->att;
	struct bt_conn *conn = att->chan.conn;
	int read;

	BT_DBG("handle 0x%04x", attr->handle);

	data->rsp = net_buf_add(data->buf, sizeof(*data->rsp));

	/*
	 * If any attribute is founded in handle range it means that error
	 * should be changed from pre-set: invalid handle error to no error.
	 */
	data->err = 0x00;

	if (!attr->read) {
		data->err = BT_ATT_ERR_READ_NOT_PERMITTED;
		return BT_GATT_ITER_STOP;
	}

	/* Check attribute permissions */
	data->err = check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
	if (data->err) {
		return BT_GATT_ITER_STOP;
	}

	/* Read attribute value and store in the buffer */
	read = attr->read(conn, attr, data->buf->data + data->buf->len,
			  att->chan.tx.mtu - data->buf->len, data->offset);
	if (read < 0) {
		data->err = err_to_att(read);
		return BT_GATT_ITER_STOP;
	}

	net_buf_add(data->buf, read);

	return BT_GATT_ITER_CONTINUE;
}
예제 #16
0
파일: shm.c 프로젝트: Hooman3/minix
/*===========================================================================*
 *				do_shmat		     		     *
 *===========================================================================*/
int do_shmat(message *m)
{
	int id, flag;
	vir_bytes addr;
	void *ret;
	struct shm_struct *shm;

	id = m->m_lc_ipc_shmat.id;
	addr = (vir_bytes) m->m_lc_ipc_shmat.addr;
	flag = m->m_lc_ipc_shmat.flag;

	if (addr && (addr % PAGE_SIZE)) {
		if (flag & SHM_RND)
			addr -= (addr % PAGE_SIZE);
		else
			return EINVAL;
	}

	if (!(shm = shm_find_id(id)))
		return EINVAL;

	if (flag & SHM_RDONLY)
		flag = 0444;
	else
		flag = 0666;
	if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag))
		return EACCES;

	ret = vm_remap(who_e, sef_self(), (void *)addr, (void *)shm->page,
			shm->shmid_ds.shm_segsz);
	if (ret == MAP_FAILED)
		return ENOMEM;

	shm->shmid_ds.shm_atime = time(NULL);
	shm->shmid_ds.shm_lpid = getnpid(who_e);
	/* nattach is updated lazily */

	m->m_lc_ipc_shmat.retaddr = ret;
	return OK;
}
예제 #17
0
파일: shm.c 프로젝트: vivekp/minix-nbsd
/*===========================================================================*
 *				do_shmat		     		     *
 *===========================================================================*/
PUBLIC int do_shmat(message *m)
{
	int id, flag;
	vir_bytes addr;
	void *ret;
	struct shm_struct *shm;

	id = m->SHMAT_ID;
	addr = (vir_bytes) m->SHMAT_ADDR;
	flag = m->SHMAT_FLAG;

	if (addr && (addr % I386_PAGE_SIZE)) {
		if (flag & SHM_RND)
			addr -= (addr % I386_PAGE_SIZE);
		else
			return EINVAL;
	}

	if (!(shm = shm_find_id(id)))
		return EINVAL;

	if (flag & SHM_RDONLY)
		flag = 0444;
	else
		flag = 0666;
	if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag))
		return EACCES;

	ret = vm_remap(who_e, SELF_E, (void *)addr, (void *)shm->page,
			shm->shmid_ds.shm_segsz);
	if (ret == MAP_FAILED)
		return ENOMEM;

	shm->shmid_ds.shm_atime = time(NULL);
	shm->shmid_ds.shm_lpid = getnpid(who_e);
	/* nattach is updated lazily */

	m->SHMAT_RETADDR = (long) ret;
	return OK;
}
예제 #18
0
파일: sem.c 프로젝트: DragonQuan/minix3
/*===========================================================================*
 *				do_semctl		     		     *
 *===========================================================================*/
PUBLIC int do_semctl(message *m)
{
	int r, i;
	long opt;
	uid_t uid;
	int id, num, cmd, val;
	unsigned short *buf;
	struct semid_ds *ds, tmp_ds;
	struct sem_struct *sem;

	id = m->SEMCTL_ID;
	num = m->SEMCTL_NUM;
	cmd = m->SEMCTL_CMD;

	if (cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_INFO ||
		cmd == SEM_INFO || cmd == SEM_STAT || cmd == GETALL ||
		cmd == SETALL || cmd == SETVAL)
		opt = m->SEMCTL_OPT;

	if (!(sem = sem_find_id(id))) {
		return EINVAL;
	}

	/* IPC_SET and IPC_RMID as its own permission check */
	if (cmd != IPC_SET && cmd != IPC_RMID) {
		/* check read permission */
		if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444))
			return EACCES;
	}

	switch (cmd) {
	case IPC_STAT:
		ds = (struct semid_ds *) opt;
		if (!ds)
			return EFAULT;
		r = sys_datacopy(SELF_E, (vir_bytes) &sem->semid_ds,
			who_e, (vir_bytes) ds, sizeof(struct semid_ds));
		if (r != OK)
			return EINVAL;
		break;
	case IPC_SET:
		uid = getnuid(who_e);
		if (uid != sem->semid_ds.sem_perm.cuid &&
			uid != sem->semid_ds.sem_perm.uid &&
			uid != 0)
			return EPERM;
		ds = (struct semid_ds *) opt;
		r = sys_datacopy(who_e, (vir_bytes) ds,
			SELF_E, (vir_bytes) &tmp_ds, sizeof(struct semid_ds));
		if (r != OK)
			return EINVAL;
		sem->semid_ds.sem_perm.uid = tmp_ds.sem_perm.uid;
		sem->semid_ds.sem_perm.gid = tmp_ds.sem_perm.gid;
		sem->semid_ds.sem_perm.mode &= ~0777;
		sem->semid_ds.sem_perm.mode |= tmp_ds.sem_perm.mode & 0666;
		sem->semid_ds.sem_ctime = time(NULL);
		break;
	case IPC_RMID:
		uid = getnuid(who_e);
		if (uid != sem->semid_ds.sem_perm.cuid &&
			uid != sem->semid_ds.sem_perm.uid &&
			uid != 0)
			return EPERM;
		/* awaken all processes block in semop
		 * and remove the semaphore set.
		 */
		update_one_semaphore(sem, 1);
		break;
	case IPC_INFO:
		break;
	case SEM_INFO:
		break;
	case SEM_STAT:
		break;
	case GETALL:
		buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
		if (!buf)
			return ENOMEM;
		for (i = 0; i < sem->semid_ds.sem_nsems; i++)
			buf[i] = sem->sems[i].semval;
		r = sys_datacopy(SELF_E, (vir_bytes) buf,
			who_e, (vir_bytes) opt,
			sizeof(unsigned short) * sem->semid_ds.sem_nsems);
		if (r != OK)
			return EINVAL;
		free(buf);
		break;
	case GETNCNT:
		if (num < 0 || num >= sem->semid_ds.sem_nsems)
			return EINVAL;
		m->SHMCTL_RET = sem->sems[num].semncnt;
		break;
	case GETPID:
		if (num < 0 || num >= sem->semid_ds.sem_nsems)
			return EINVAL;
		m->SHMCTL_RET = sem->sems[num].sempid;
		break;
	case GETVAL:
		if (num < 0 || num >= sem->semid_ds.sem_nsems)
			return EINVAL;
		m->SHMCTL_RET = sem->sems[num].semval;
		break;
	case GETZCNT:
		if (num < 0 || num >= sem->semid_ds.sem_nsems)
			return EINVAL;
		m->SHMCTL_RET = sem->sems[num].semzcnt;
		break;
	case SETALL:
		buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
		if (!buf)
			return ENOMEM;
		r = sys_datacopy(who_e, (vir_bytes) opt,
			SELF_E, (vir_bytes) buf,
			sizeof(unsigned short) * sem->semid_ds.sem_nsems);
		if (r != OK)
			return EINVAL;
#ifdef DEBUG_SEM
		printf("SEMCTL: SETALL: opt: %p\n");
		for (i = 0; i < sem->semid_ds.sem_nsems; i++)
			printf("SEMCTL: SETALL val: [%d] %d\n", i, buf[i]);
#endif
		for (i = 0; i < sem->semid_ds.sem_nsems; i++) {
			if (buf[i] < 0 || buf[i] > SEMVMX) {
				free(buf);
				update_semaphores();
				return ERANGE;
			}
			sem->sems[i].semval = buf[i];
		}
		free(buf);
		/* awaken if possible */
		update_semaphores();
		break;
	case SETVAL:
		val = (int) opt;
		/* check write permission */
		if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
			return EACCES;
		if (num < 0 || num >= sem->semid_ds.sem_nsems)
			return EINVAL;
		if (val < 0 || val > SEMVMX)
			return ERANGE;
		sem->sems[num].semval = val;
#ifdef DEBUG_SEM
		printf("SEMCTL: SETVAL: %d %d\n", num, val);
#endif
		sem->semid_ds.sem_ctime = time(NULL);
		/* awaken if possible */
		update_semaphores();
		break;
	default:
		return EINVAL;
	}

	return OK;
}
예제 #19
0
파일: att.c 프로젝트: PchZhang/testgit
static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
{
	struct read_type_data *data = user_data;
	struct bt_att *att = data->att;
	struct bt_conn *conn = att->chan.conn;
	int read;

	/* Skip if doesn't match */
	if (bt_uuid_cmp(attr->uuid, data->uuid)) {
		return BT_GATT_ITER_CONTINUE;
	}

	BT_DBG("handle 0x%04x", attr->handle);

	/*
	 * If an attribute in the set of requested attributes would cause an
	 * Error Response then this attribute cannot be included in a
	 * Read By Type Response and the attributes before this attribute
	 * shall be returned
	 *
	 * If the first attribute in the set of requested attributes would
	 * cause an Error Response then no other attributes in the requested
	 * attributes can be considered.
	 */
	data->err = check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
	if (data->err) {
		if (data->rsp->len) {
			data->err = 0x00;
		}
		return BT_GATT_ITER_STOP;
	}

	/*
	 * If any attribute is founded in handle range it means that error
	 * should be changed from pre-set: attr not found error to no error.
	 */
	data->err = 0x00;

	/* Fast foward to next item position */
	data->item = net_buf_add(data->buf, sizeof(*data->item));
	data->item->handle = sys_cpu_to_le16(attr->handle);

	/* Read attribute value and store in the buffer */
	read = attr->read(conn, attr, data->buf->data + data->buf->len,
			  att->chan.tx.mtu - data->buf->len, 0);
	if (read < 0) {
		data->err = err_to_att(read);
		return BT_GATT_ITER_STOP;
	}

	if (!data->rsp->len) {
		/* Set len to be the first item found */
		data->rsp->len = read + sizeof(*data->item);
	} else if (data->rsp->len != read + sizeof(*data->item)) {
		/* All items should have the same size */
		data->buf->len -= sizeof(*data->item);
		return BT_GATT_ITER_STOP;
	}

	net_buf_add(data->buf, read);

	/* return true only if there are still space for more items */
	return att->chan.tx.mtu - data->buf->len > data->rsp->len ?
	       BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
}
예제 #20
0
파일: sem.c 프로젝트: DragonQuan/minix3
/*===========================================================================*
 *				do_semop		     		     *
 *===========================================================================*/
PUBLIC int do_semop(message *m)
{
	int id, i, j, r;
	struct sembuf *sops;
	unsigned int nsops;
	struct sem_struct *sem;
	int no_reply = 0;

	id = m->SEMOP_ID;
	nsops = (unsigned int) m->SEMOP_SIZE;

	r = EINVAL;
	if (!(sem = sem_find_id(id)))
		goto out;

	if (nsops <= 0)
		goto out;

	r = E2BIG;
	if (nsops > SEMOPM)
		goto out;

	/* check for read permission */
	r = EACCES;
	if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444))
		goto out;

	/* get the array from user application */
	r = ENOMEM;
	sops = malloc(sizeof(struct sembuf) * nsops);
	if (!sops)
		goto out_free;
	r = sys_datacopy(who_e, (vir_bytes) m->SEMOP_OPS,
			SELF_E, (vir_bytes) sops,
			sizeof(struct sembuf) * nsops);
	if (r != OK) {
		r = EINVAL;
		goto out_free;
	}

#ifdef DEBUG_SEM
	for (i = 0; i < nsops; i++)
		printf("SEMOP: num:%d  op:%d  flg:%d\n",
			sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg);
#endif
	/* check for value range */
	r = EFBIG;
	for (i = 0; i < nsops; i++)
		if (sops[i].sem_num < 0 ||
				sops[i].sem_num >= sem->semid_ds.sem_nsems)
			goto out_free;

	/* check for duplicate number */
	r = EINVAL;
	for (i = 0; i < nsops; i++)
		for (j = i + 1; j < nsops; j++)
			if (sops[i].sem_num == sops[j].sem_num)
				goto out_free;

	/* check for EAGAIN error */
	r = EAGAIN;
	for (i = 0; i < nsops; i++) {
		int op_n, val;

		op_n = sops[i].sem_op;
		val = sem->sems[sops[i].sem_num].semval;

		if ((sops[i].sem_flg & IPC_NOWAIT) &&
				((!op_n && val) ||
				 (op_n < 0 &&
				  -op_n > val)))
			goto out_free;

	}
	/* there will be no errors left, so we can go ahead */
	for (i = 0; i < nsops; i++) {
		struct semaphore *s;
		int op_n;

		s = &sem->sems[sops[i].sem_num];
		op_n = sops[i].sem_op;

		s->sempid = getnpid(who_e);

		if (op_n > 0) {
			/* check for alter permission */
			r = EACCES;
			if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
				goto out_free;
			s->semval += sops[i].sem_op;
		} else if (!op_n) {
			if (s->semval) {
				/* put the process asleep */
				s->semzcnt++;
				s->zlist = realloc(s->zlist, sizeof(struct waiting) * s->semzcnt);
				if (!s->zlist) {
					printf("IPC: zero waiting list lost...\n");
					break;
				}
				s->zlist[s->semzcnt-1].who = who_e;
				s->zlist[s->semzcnt-1].val = op_n;

#ifdef DEBUG_SEM
				printf("SEMOP: Put into sleep... %d\n", who_e);
#endif
				no_reply++;
			}
		} else {
			/* check for alter permission */
			r = EACCES;
			if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
				goto out_free;
			if (s->semval >= -op_n)
				s->semval += op_n;
			else {
				/* put the process asleep */
				s->semncnt++;
				s->nlist = realloc(s->nlist, sizeof(struct waiting) * s->semncnt);
				if (!s->nlist) {
					printf("IPC: increase waiting list lost...\n");
					break;
				}
				s->nlist[s->semncnt-1].who = who_e;
				s->nlist[s->semncnt-1].val = -op_n;

				no_reply++;
			}
		}
	}

	r = OK;
out_free:
	free(sops);
out:
	/* if we reach here by errors
	 * or with no errors but we should reply back.
	 */
	if (r != OK || !no_reply) {
		m->m_type = r;

		sendnb(who_e, m);
	}

	/* awaken process if possible */
	update_semaphores();

	return 0;
}
예제 #21
0
static int mount_fuse(const char *mnt, const char *opts, char *devfd)
{
	int res;
	int fd;
	char *dev;
	struct stat stbuf;
	char *type = NULL;
	char *source = NULL;
	char *mnt_opts = NULL;
	const char *real_mnt = mnt;
	int mountpoint_fd = -1;

	fd = devfd ? check_fuse_device(devfd, &dev) : open_fuse_device(&dev);
	if (fd == -1)
		return -1;

	drop_privs();
	read_conf();

	if (getuid() != 0 && mount_max != -1) {
		int mount_count = count_fuse_fs();
		if (mount_count >= mount_max) {
			fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
			goto fail_close_fd;
		}
	}

	res = check_version(dev);
	if (res != -1) {
		res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
		restore_privs();
		if (res != -1)
			res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
				       fd, opts, dev, &source, &mnt_opts,
				       stbuf.st_size);
	} else
		restore_privs();

	if (mountpoint_fd != -1)
		close(mountpoint_fd);

	if (res == -1)
		goto fail_close_fd;

	res = chdir("/");
	if (res == -1) {
		fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
		goto fail_close_fd;
	}

	if (geteuid() == 0) {
		res = add_mount(source, mnt, type, mnt_opts);
		if (res == -1) {
			/* Can't clean up mount in a non-racy way */
			goto fail_close_fd;
		}
	}

out_free:
	free(source);
	free(type);
	free(mnt_opts);
	free(dev);

	return fd;

fail_close_fd:
	close(fd);
	fd = -1;
	goto out_free;
}
예제 #22
0
파일: validate.c 프로젝트: bumper-app/nicad
/**
 * Validate a given device service s.  Events are posted according to 
 * its configuration.  In case of a fatal event FALSE is returned.
 */
int check_device(Service_T s) {

  Device_T td;
  struct stat stat_buf;
  char report[STRLEN]= {0};

  if(stat(s->path, &stat_buf) != 0) {
    if(! s->event_handled) {
      Event_post(s, EVENT_START, "Event: device '%s' doesn't exist\n", s->name);
      s->event_handled= TRUE;
    }
    return FALSE;
  } else {
    s->event_handled= FALSE;
  }
  
  if(check_perm(s, stat_buf.st_mode, report)) {
    s->perm->event_flag= TRUE;
    if(! eval_actions(s->perm->action, s, report, "permission",
		      EVENT_PERMISSION))
      return FALSE;
  }

  if(check_uid(s, stat_buf.st_uid, report)) {
    s->uid->event_flag= TRUE;
    if(! eval_actions(s->uid->action, s, report, "uid", EVENT_UID))
      return FALSE;
  }

  if(check_gid(s, stat_buf.st_gid, report)) {
    s->gid->event_flag= TRUE;
    if(! eval_actions(s->gid->action, s, report, "gid", EVENT_GID))
      return FALSE;
  }

  if(!DeviceInfo_Usage(s->devinfo, s->path)) {
    if(! s->devinfo->event_handled) {
      Event_post(s, EVENT_START,
		 "Event: unable to read device '%s' state\n",
		 s->path);
      s->devinfo->event_handled= TRUE;
    }
    return FALSE;
  } else {
    s->devinfo->event_handled= FALSE;
    DEBUG("'%s' succeeded getting device statistic for %s\n", s->name, s->path);
  }

  /* Test devices */
  if(s->devicelist) {
    for(td= s->devicelist; td; td= td->next) {
      if(!check_device_resources(s, td, report)) {
	if(! td->event_handled) {
	  td->event_flag= TRUE; /* Turn on the object's event_flag
				 * to indicate that the resource
				 * event occured on this particular
				 * object */
	  td->event_handled= TRUE; /* Turn on the object's
				    * event_handled flag so this
				    * test is not handled in
				    * subsequent poll cycles until
				    * the error condition was reset.
				    */

	  if(! eval_actions(td->action, s, report, "device", EVENT_RESOURCE)) {
	    return FALSE;
	  }
	}
      } else {
	td->event_handled= FALSE; 
      }
    }
    
  }
  
  return TRUE;

}
예제 #23
0
파일: validate.c 프로젝트: bumper-app/nicad
/**
 * Validate a given file service s.  Events are posted according to 
 * its configuration.  In case of a fatal event FALSE is returned.
 */
int check_file(Service_T s) {

  Size_T sl;
  struct stat stat_buf;
  char report[STRLEN]= {0};

  if(stat(s->path, &stat_buf) != 0) {
    if(! s->event_handled) {
      Event_post(s, EVENT_START, "Event: file '%s' doesn't exist\n", s->name);
      s->event_handled= TRUE;
    }
    return FALSE;
  } else {
    s->event_handled= TRUE;
  }
  
  if(!S_ISREG(stat_buf.st_mode)) {
    if(! s->event_handled) {
      Event_post(s, EVENT_UNMONITOR,
		 "Event: '%s' is not regular file\n", s->name);
      s->event_handled= TRUE;
    }
    return FALSE;
  } else {
    s->event_handled= FALSE;
  }
  
  if(check_checksum(s, report)) {
      s->checksum->event_flag= TRUE;
      if(! eval_actions(s->checksum->action, s, report, "checksum",
			EVENT_CHECKSUM))
	  return FALSE;
  }
  
  if(check_perm(s, stat_buf.st_mode, report)) {
    s->perm->event_flag= TRUE;
    if(! eval_actions(s->perm->action, s, report, "permission",
		      EVENT_PERMISSION))
	return FALSE;
  }

  if(check_uid(s, stat_buf.st_uid, report)) {
    s->uid->event_flag= TRUE;
    if(! eval_actions(s->uid->action, s, report, "uid", EVENT_UID))
	return FALSE;
  }
  
  if(check_gid(s, stat_buf.st_gid, report)) {
    s->gid->event_flag= TRUE;
    if(! eval_actions(s->gid->action, s, report, "gid", EVENT_GID))
	return FALSE;
  }

  for(sl= s->sizelist; sl; sl= sl->next) {
    if(!check_size_item(s, sl, (unsigned long)stat_buf.st_size, report)) {
      if(! sl->event_handled) {
	/* Turn on the object's event_flag to indicate that the size event
	 * occured on this particular object */
	sl->event_flag= TRUE;
	sl->event_handled= TRUE; /* Turn on the object's
				  * event_handled flag so this
				  * test is not handled in
				  * subsequent poll cycles until
				  * the error condition was reset.
				  */
	if(! eval_actions(sl->action, s, report, "size", EVENT_SIZE)) {
	  return FALSE;
	}
      }
    } else {
      sl->event_handled= FALSE;
    }
  }

  if(!check_timestamps(s))
    return FALSE;

  return TRUE;

}
예제 #24
0
파일: file.c 프로젝트: 383530895/linux
static int configfs_open_file(struct inode * inode, struct file * filp)
{
	return check_perm(inode,filp);
}
예제 #25
0
int * implicit_enum(struct row_vertex * main_col, int lower_bound, int upper_bound, int * vertices, int vertex_num) {
  int i;
  int used_colors[vertex_num];
  int * color_count = (int *) malloc(sizeof(int));
  int color;
  int flag; //Para saber cuando se deja de ampliar la primera clique encontrada
  int out;
  int leftover = vertex_num - lower_bound; //Tamaño del resto a permutar
  //Arreglo con vértices que pertenecen a cota inferior de brelaz
  int * fixed = (int *) malloc(sizeof(int) * lower_bound);
  int fixed_s = lower_bound; //Tamaño de arreglo fijo
  //Arreglo con vértices que no están en la cota inferior de brelaz
  int * permuta = (int *) malloc(sizeof(int) * leftover);
  //Inicializar fixed
  for(i = 0; i < fixed_s; i++)
    fixed[i] = vertices[i];
  //Inicializar permuta
  for(i = 0; i < leftover; i++) 
    permuta[i] = vertices[fixed_s + i];

  int stop = 0;
  while(!stop) {

    //Inicialización de estructura de adyacencias y colores usados
    main_col_init(main_col, vertex_num); 
    initialize(used_colors, vertex_num);
    *color_count = 0;
    //Colorear vértices fijos
    color_fixed(fixed, main_col, fixed_s, used_colors, color_count); 
    flag = 1;
    out = 0;
    stop = check_perm(permuta, leftover);
    for(i = 0; i < leftover; i++) { 
      color = leastp_color(main_col, permuta[i], vertex_num);
      main_col[permuta[i]].color = color;
      if (used_colors[color] == 0) {
        (*color_count)++;
        used_colors[color] = 1;
        if (flag && *color_count > lower_bound) { //Actualizar cota inferior ?
          //Si cota inferior se hace igual a cota 
          //superior hay que retornar !
          lower_bound = *color_count; 
        }
      }
      else 
        flag = 0;    //No se sigue ampliando la clique encontrada
      if (lower_bound == upper_bound) {
        free(fixed);
        free(permuta);
        return color_count;
      }
      if (*color_count == upper_bound) {
        out = 1;
        break;
      }
      //Actualizamos vértices adyacentes con color usado
      update_color_around(main_col, permuta[i], color);
    }
    if (*color_count == lower_bound) {
      free(fixed);
      free(permuta);
      return color_count;  //Número cromático
    }
    if (*color_count < upper_bound)
      upper_bound = *color_count;
    if (out) { //Ocurrió que se alcanzó cota superior
      next_perm(permuta, leftover);      
      continue;
    }
    //Próxima permutación
    next_perm(permuta, leftover);
  } 

  free(fixed);
  int * solution = (int *) malloc(sizeof(int));
  *solution = upper_bound;
  return solution;
}
예제 #26
0
static int configfs_open_bin_file(struct inode *inode, struct file *filp)
{
    return check_perm(inode, filp,
                      configfs_get_config_item(filp->f_path.dentry->d_parent),
                      to_attr(filp->f_path.dentry), CONFIGFS_ITEM_BIN_ATTR);
}
예제 #27
0
파일: shm.c 프로젝트: vivekp/minix-nbsd
/*===========================================================================*
 *				do_shmget		     		     *
 *===========================================================================*/
PUBLIC int do_shmget(message *m)
{
	struct shm_struct *shm;
	long key, size, old_size;
	int flag;
	int id;

	key = m->SHMGET_KEY;
	old_size = size = m->SHMGET_SIZE;
	flag = m->SHMGET_FLAG;

	if ((shm = shm_find_key(key))) {
		if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag))
			return EACCES;
		if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
			return EEXIST;
		if (size && shm->shmid_ds.shm_segsz < size)
			return EINVAL;
		id = shm->id;
	} else { /* no key found */
		if (!(flag & IPC_CREAT))
			return ENOENT;
		if (size <= 0)
			return EINVAL;
		/* round up to a multiple of PAGE_SIZE */
		if (size % I386_PAGE_SIZE)
			size += I386_PAGE_SIZE - size % I386_PAGE_SIZE;
		if (size <= 0)
			return EINVAL;

		if (shm_list_nr == MAX_SHM_NR)
			return ENOMEM;
		/* TODO: shmmni should be changed... */
		if (identifier == SHMMNI)
			return ENOSPC;
		shm = &shm_list[shm_list_nr];
		memset(shm, 0, sizeof(struct shm_struct));
		shm->page = (vir_bytes) mmap(0, size,
					PROT_READ|PROT_WRITE,
					MAP_CONTIG|MAP_PREALLOC|MAP_ANON|MAP_SHARED,
					-1, 0);
		if (shm->page == (vir_bytes) MAP_FAILED)
			return ENOMEM;
		shm->phys = vm_getphys(SELF_E, (void *) shm->page);
		memset((void *)shm->page, 0, size);

		shm->shmid_ds.shm_perm.cuid =
			shm->shmid_ds.shm_perm.uid = getnuid(who_e);
		shm->shmid_ds.shm_perm.cgid =
			shm->shmid_ds.shm_perm.gid = getngid(who_e);
		shm->shmid_ds.shm_perm.mode = flag & 0777;
		shm->shmid_ds.shm_segsz = old_size;
		shm->shmid_ds.shm_atime = 0;
		shm->shmid_ds.shm_dtime = 0;
		shm->shmid_ds.shm_ctime = time(NULL);
		shm->shmid_ds.shm_cpid = getnpid(who_e);
		shm->shmid_ds.shm_lpid = 0;
		shm->shmid_ds.shm_nattch = 0;
		shm->id = id = identifier++;
		shm->key = key;

		shm_list_nr++;
	}

	m->SHMGET_RETID = id;
	return OK;
}
예제 #28
0
파일: file.c 프로젝트: a2hojsjsjs/linux
static int configfs_open_bin_file(struct inode *inode, struct file *filp)
{
	return check_perm(inode, filp, CONFIGFS_ITEM_BIN_ATTR);
}
예제 #29
0
int
main(int argc, char **argv)
{
	int ch, ret = 0, rflag = 0, argindex, tries;
	struct passwd *pstruct;
	struct stat statbuf;
#ifndef att
	FILE *pwf;		/* fille ptr for opened passwd file */
#endif
	char *usertype = NULL;
	int rc;

	cmdname = argv[0];

	if( geteuid() != 0 ) {
		errmsg( M_PERM_DENIED );
		exit( EX_NO_PERM );
	}

	opterr = 0;			/* no print errors from getopt */
	usertype = getusertype(argv[0]);
	
	while( (ch = getopt(argc, argv, "r")) != EOF ) {
		switch(ch) {
			case 'r':
				rflag++;
				break;
			case '?':
				if (is_role(usertype))
					errmsg( M_DRUSAGE );
				else
					errmsg( M_DUSAGE );
				exit( EX_SYNTAX );
		}
	}

	if( optind != argc - 1 ) {
		if (is_role(usertype))
			errmsg( M_DRUSAGE );
		else
			errmsg( M_DUSAGE );
		exit( EX_SYNTAX );
	}

	logname = argv[optind];

#ifdef att
	pstruct = getpwnam(logname);
#else
	/*
	 * Do this with fgetpwent to make sure we are only looking on local
	 * system (since passmgmt only works on local system).
	 */
	if ((pwf = fopen("/etc/passwd", "r")) == NULL) {
		errmsg( M_OOPS, "open", "/etc/passwd");
		exit(EX_FAILURE);
	}
	while ((pstruct = fgetpwent(pwf)) != NULL)
		if (strcmp(pstruct->pw_name, logname) == 0)
			break;

	fclose(pwf);
#endif

	if (pstruct == NULL) {
		errmsg( M_EXIST, logname );
		exit( EX_NAME_NOT_EXIST );
	}

	if( isbusy(logname) ) {
		errmsg( M_BUSY, logname, "remove" );
		exit( EX_BUSY );
	}

	/* that's it for validations - now do the work */
	/* set up arguments to  passmgmt in nargv array */
	nargv[0] = PASSMGMT;
	nargv[1] = "-d";	/* delete */
	argindex = 2;		/* next argument */

	/* finally - login name */
	nargv[argindex++] = logname;

	/* set the last to null */
	nargv[argindex++] = NULL;

	/* remove home directory */
	if( rflag ) {
		/* Check Permissions */
		if( stat( pstruct->pw_dir, &statbuf ) ) {
			errmsg(M_OOPS, "find status about home directory", 
			    strerror(errno));
			exit( EX_HOMEDIR );
		}
			
		if( check_perm( statbuf, pstruct->pw_uid, pstruct->pw_gid,
		    S_IWOTH|S_IXOTH ) != 0 ) {
			errmsg( M_NO_PERM, logname, pstruct->pw_dir );
			exit( EX_HOMEDIR );
		}

		if( rm_files(pstruct->pw_dir, logname) != EX_SUCCESS ) 
			exit( EX_HOMEDIR );
	}

	/* now call passmgmt */
	ret = PEX_FAILED;
	for( tries = 3; ret != PEX_SUCCESS && tries--; ) {
		switch( ret = call_passmgmt( nargv ) ) {
		case PEX_SUCCESS:
			ret = edit_group( logname, (char *)0, (int **)0, 1 );
			if( ret != EX_SUCCESS )
				errmsg( M_UPDATE, "deleted" );
			break;

		case PEX_BUSY:
			break;

		case PEX_HOSED_FILES:
			errmsg( M_HOSED_FILES );
			exit( EX_INCONSISTENT );
			break;

		case PEX_SYNTAX:
		case PEX_BADARG:
			/* should NEVER occur that passmgmt usage is wrong */
			if (is_role(usertype))
				errmsg( M_DRUSAGE );
			else
				errmsg( M_DUSAGE );
			exit( EX_SYNTAX );
			break;

		case PEX_BADUID:
			/* uid is used - shouldn't happen but print message anyway */
			errmsg( M_UID_USED, pstruct->pw_uid );
			exit( EX_ID_EXISTS );
			break;

		case PEX_BADNAME:
			/* invalid loname */
			errmsg( M_USED, logname);
			exit( EX_NAME_EXISTS );
			break;

		default:
			errmsg( M_UPDATE, "deleted" );
			exit( ret );
			break;
		}
	}
	if( tries == 0 ) 
		errmsg( M_UPDATE, "deleted" );

/*
 * Now, remove this user from all project entries
 */

	rc = edit_project(logname, (char *)0, (projid_t **)0, 1);
	if (rc != EX_SUCCESS) {
		errmsg(M_UPDATE, "modified");
		exit(rc);
	}
	
	exit( ret );
	/*NOTREACHED*/
}
예제 #30
0
파일: shm.c 프로젝트: vivekp/minix-nbsd
/*===========================================================================*
 *				do_shmctl		     		     *
 *===========================================================================*/
PUBLIC int do_shmctl(message *m)
{
	int id = m->SHMCTL_ID;
	int cmd = m->SHMCTL_CMD;
	struct shmid_ds *ds = (struct shmid_ds *)m->SHMCTL_BUF;
	struct shmid_ds tmp_ds;
	struct shm_struct *shm;
	struct shminfo sinfo;
	struct shm_info s_info;
	uid_t uid;
	int r, i;

	if (cmd == IPC_STAT)
		update_refcount_and_destroy();

	if ((cmd == IPC_STAT ||
		cmd == IPC_SET ||
		cmd == IPC_RMID) &&
		!(shm = shm_find_id(id)))
		return EINVAL;

	switch (cmd) {
	case IPC_STAT:
		if (!ds)
			return EFAULT;
		/* check whether it has read permission */
		if (!check_perm(&shm->shmid_ds.shm_perm, who_e, 0444))
			return EACCES;
		r = sys_datacopy(SELF_E, (vir_bytes)&shm->shmid_ds,
			who_e, (vir_bytes)ds, sizeof(struct shmid_ds));
		if (r != OK)
			return EFAULT;
		break;
	case IPC_SET:
		uid = getnuid(who_e);
		if (uid != shm->shmid_ds.shm_perm.cuid &&
			uid != shm->shmid_ds.shm_perm.uid &&
			uid != 0)
			return EPERM;
		r = sys_datacopy(who_e, (vir_bytes)ds,
			SELF_E, (vir_bytes)&tmp_ds, sizeof(struct shmid_ds));
		if (r != OK)
			return EFAULT;
		shm->shmid_ds.shm_perm.uid = tmp_ds.shm_perm.uid;
		shm->shmid_ds.shm_perm.gid = tmp_ds.shm_perm.gid;
		shm->shmid_ds.shm_perm.mode &= ~0777;
		shm->shmid_ds.shm_perm.mode |= tmp_ds.shm_perm.mode & 0666;
		shm->shmid_ds.shm_ctime = time(NULL);
		break;
	case IPC_RMID:
		uid = getnuid(who_e);
		if (uid != shm->shmid_ds.shm_perm.cuid &&
			uid != shm->shmid_ds.shm_perm.uid &&
			uid != 0)
			return EPERM;
		shm->shmid_ds.shm_perm.mode |= SHM_DEST;
		/* destroy if possible */
		update_refcount_and_destroy();
		break;
	case IPC_INFO:
		if (!ds)
			return EFAULT;
		sinfo.shmmax = (unsigned long) -1;
		sinfo.shmmin = 1;
		sinfo.shmmni = MAX_SHM_NR;
		sinfo.shmseg = (unsigned long) -1;
		sinfo.shmall = (unsigned long) -1;
		r = sys_datacopy(SELF_E, (vir_bytes)&sinfo,
			who_e, (vir_bytes)ds, sizeof(struct shminfo));
		if (r != OK)
			return EFAULT;
		m->SHMCTL_RET = shm_list_nr - 1;
		if (m->SHMCTL_RET < 0)
			m->SHMCTL_RET = 0;
		break;
	case SHM_INFO:
		if (!ds)
			return EFAULT;
		s_info.used_ids = shm_list_nr;
		s_info.shm_tot = 0;
		for (i = 0; i < shm_list_nr; i++)
			s_info.shm_tot +=
				shm_list[i].shmid_ds.shm_segsz/I386_PAGE_SIZE;
		s_info.shm_rss = s_info.shm_tot;
		s_info.shm_swp = 0;
		s_info.swap_attempts = 0;
		s_info.swap_successes = 0;
		r = sys_datacopy(SELF_E, (vir_bytes)&s_info,
			who_e, (vir_bytes)ds, sizeof(struct shm_info));
		if (r != OK)
			return EFAULT;
		m->SHMCTL_RET = shm_list_nr - 1;
		if (m->SHMCTL_RET < 0)
			m->SHMCTL_RET = 0;
		break;
	case SHM_STAT:
		if (id < 0 || id >= shm_list_nr)
			return EINVAL;
		shm = &shm_list[id];
		r = sys_datacopy(SELF_E, (vir_bytes)&shm->shmid_ds,
			who_e, (vir_bytes)ds, sizeof(struct shmid_ds));
		if (r != OK)
			return EFAULT;
		m->SHMCTL_RET = shm->id;
		break;
	default:
		return EINVAL;
	}
	return OK;
}