[OpenIndiana-discuss] Solaris privileges and seteuid()

Frank Lahm franklahm at gmail.com
Wed Aug 15 13:38:35 UTC 2012


Hi all,

I'm having difficulties with Solaris privileges and seteuid().

I have a forking daemon process running as root. The process is afpd
from the Netatalk (OS AFP fileserver). The main afpd process accepts
network connections, authenticates users (through PAM) and, forks and
runs seteuid(USER).
Occasionally the process calls seteuid(0) to execute priviliged
operations and then goes seteuid(USER) back again.

This all works find with local Solaris users. Now I've added Active
Directory to the mix (smbadm join, nss_ad, pam_krb5). Works fine
execpt for one issue which is a result of the following idmap
restriction

   man idmap
   ...
     To prevent aliasing problems, all file systems, archive  and
     backup  formats,  and  protocols  must store SIDs or map all
     UIDs and GIDs in the 2^31 to 2^32 - 2 range  to  the  nobody
     user and group.
   ...

This means any file created by an afpd process (Solaris CIFS/NFS don't
have this issue) running with the effective uid of an AD user is
created with and owner/group of nobody:

  root at oi:~# ps -elf | grep aduser
   0 S aduser at a 12440 12193 0  40 20  ?   4518  ? 15:03:12 ?  0:00
/usr/local/netatalk/sbin/afpd -d -F

  root at oi:~# pcred 12440
  12440:  euid=2147500125 ruid=0 suid=0  egid=2147491842 rgid=0 sgid=0

  root at oi:~# getent passwd aduser at ad.hh.netafp.com
  aduser at ad.hh.netafp.com:x:2147500125:2147491842:AD User::/bin/sh

...create file via AFP (touch /Volumes/test/afpfile1 on a Mac)...

  root at oi:~# ls -l /Volumes/test/afpfile1
  -rw-rw-rw-   1 nobody   nobody         0 Aug 15 15:04 /Volumes/test/afpfile1

The file "afpfile1" was created by the afpd process [12440] with a
call to open(...O_CREAT...).

I know from writing a simple test program (see below) that a possible
workaround to enforce owner/group for file is just calling chown on
them. This works with chown(1)

  root at oi:~# chown aduser at ad.hh.netafp.com /Volumes/test/afpfile1
  root at oi:~# ls -l /Volumes/test/afpfile1
  -rw-rw-rw-   1 aduser at ad.hh.netafp.com nobody         0 Aug 15 15:04
/Volumes/test/afpfile1

...and it works in the test program, unfortunately it doesn't work for
afpd, all I get is EPERM (missing privilege file_chown_self). As I'm
wrapping the fchwon call between seteuid(0) and seteuid(USER) and I've
also verified that PAS (privilege awareness state) for the process is
0 by call getpflags(PRIV_AWARE) before the call to chmod:

Code:
    LOG(log_note, logtype_afpd, "afp_createfile: PAS: %s",
getpflags(PRIV_AWARE) ? "PRIV_AWARE" : "not PRIV_AWARE");

Log:
    Aug 15 15:06:42.083590 afpd[12440] {file.c:732} (N:AFPDaemon):
afp_createfile: PAS: not PRIV_AWARE

truss shows:

  root at oi:~# truss -v all -t fchown,seteuid -p 12440
  seteuid(0)                                      = 0
  fchown(10, -2147467171, -2147475454)            Err#1 EPERM [file_chown_self]
  seteuid(2147500125)                             = 0

The negative uid and gid for fchown are ok, truss interprets the
ephemeral ids (defined to be >0x8000000) as negative numbers.

  root at oi:~# ppriv 12440
  12440:  /usr/local/netatalk/sbin/afpd -d -F /usr/local/netatalk/etc/afp.conf
  flags = <none>
          E: basic
          I: basic
          P: all
          L: all

No matter what I try (increasing privileges for the process with eg
ppriv -s EIPL=all PID), it always fails with EPERM which strikes me as
it is demonstratably doing the fchown() with an effective uid of 0.

I highly appreciate any insight or pointers. There's a budget for paid
consulting, you can also contact me by PM if your interested and you
think you can help.

Thank you!
-f

---8<---
/*
 * gcc -o seteuid seteuid.c
 */

#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <pwd.h>

#define ERROR(msg) do { perror(msg); exit(1); } while (0)

int wait_for_key(void)
{
    printf(" [Press RETURN to continue...]");
    getchar();
}

int main (int argc, char **argv)
{
    struct stat st;
    const char *name, *file;
    struct passwd *pwd;
    int fd;

    if (argc < 3) {
        printf("usage: %s USERNAME FILENAME\n", argv[0]);
        exit(1);
    }

    name = argv[1];
    file = argv[2];

    if (getuid() != 0) {
        printf("Must be run with uid 0 (root)\n");
        exit(1);
    }

    if ((pwd = getpwnam(name)) == NULL)
        ERROR("getpwnam");

    printf("name: %s, uid: %u\n", name, pwd->pw_uid);

    printf("switching effective uid to %u", pwd->pw_uid);
    wait_for_key();

    if (seteuid(pwd->pw_uid) != 0)
        ERROR("seteuid");

    printf("creating file ...");
    wait_for_key();

    if ((fd = creat(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
        ERROR("creat");

    if (fstat(fd, &st) != 0)
        ERROR("fstat");

    printf("file owner uid: %u\n", st.st_uid);

    printf("switch effective uid back to 0 (root) ...");
    wait_for_key();

    if (seteuid(0) != 0)
        ERROR("seteuid");

    printf("Try to change owner of testfile to %u", pwd->pw_uid);
    wait_for_key();

    if (fchown(fd, pwd->pw_uid) != 0)
        ERROR("fchown");

    close(fd);
    return 0;
}
---8<---



More information about the OpenIndiana-discuss mailing list