#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */
typedef scalar_t__ uid_t;
struct passwd {
  unsigned long pw_name;
  char *pw_dir;
  scalar_t__ pw_gid;
};

/* Variables and functions */
int chdir(char *);
int initgroups(unsigned long, scalar_t__);
int /*<<< orphan*/ perr(char *, ...);
int setegid(scalar_t__);
int seteuid(scalar_t__);
int setgid(scalar_t__);
int setlogin(unsigned long);
int setsid();
int setuid(scalar_t__);
void become_user(struct passwd *pentry, uid_t uid) {
  if (initgroups(pentry->pw_name, pentry->pw_gid) == -1)
    perr("Cannot init group list for `%s'", pentry->pw_name);
  if (setegid(pentry->pw_gid) == -1 || setgid(pentry->pw_gid) == -1)
    perr("Cannot change primary group to %lu", (unsigned long)pentry->pw_gid);
  if (setsid() == -1)
    perr("Cannot create a session");
  if (setlogin(pentry->pw_name) == -1)
    perr("Cannot set login name to `%s'", pentry->pw_name);
  if (setuid(uid) == -1 || seteuid(uid) == -1)
    perr("Cannot set user id to %lu", (unsigned long)uid);
  if (chdir(pentry->pw_dir) == -1)
    (void)chdir("/");
}


x86 assembly (clang, -O0):
<become_user>:
push   %rbp
mov    %rsp,%rbp
sub    $0x10,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    -0x8(%rbp),%rax
mov    (%rax),%rdi
mov    -0x8(%rbp),%rax
mov    0x10(%rax),%rsi
call   1090 <initgroups@plt>
cmp    $0xffffffff,%eax
jne    11d2 <become_user+0x42>
mov    -0x8(%rbp),%rax
mov    (%rax),%rsi
lea    0xe35(%rip),%rdi
mov    $0x0,%al
call   1040 <perr@plt>
mov    -0x8(%rbp),%rax
mov    0x10(%rax),%rdi
call   10a0 <setegid@plt>
cmp    $0xffffffff,%eax
je     11fe <become_user+0x6e>
mov    -0x8(%rbp),%rax
mov    0x10(%rax),%rdi
call   1060 <setgid@plt>
cmp    $0xffffffff,%eax
jne    1214 <become_user+0x84>
mov    -0x8(%rbp),%rax
mov    0x10(%rax),%rsi
lea    0xe13(%rip),%rdi
mov    $0x0,%al
call   1040 <perr@plt>
mov    $0x0,%al
call   1050 <setsid@plt>
cmp    $0xffffffff,%eax
jne    1232 <become_user+0xa2>
lea    0xe18(%rip),%rdi
mov    $0x0,%al
call   1040 <perr@plt>
mov    -0x8(%rbp),%rax
mov    (%rax),%rdi
call   1080 <setlogin@plt>
cmp    $0xffffffff,%eax
jne    125c <become_user+0xcc>
mov    -0x8(%rbp),%rax
mov    (%rax),%rsi
lea    0xe06(%rip),%rdi
mov    $0x0,%al
call   1040 <perr@plt>
mov    -0x10(%rbp),%rdi
call   1070 <setuid@plt>
cmp    $0xffffffff,%eax
je     1280 <become_user+0xf0>
mov    -0x10(%rbp),%rdi
call   10b0 <seteuid@plt>
cmp    $0xffffffff,%eax
jne    1292 <become_user+0x102>
mov    -0x10(%rbp),%rsi
lea    0xdee(%rip),%rdi
mov    $0x0,%al
call   1040 <perr@plt>
mov    -0x8(%rbp),%rax
mov    0x8(%rax),%rdi
call   1030 <chdir@plt>
cmp    $0xffffffff,%eax
jne    12b4 <become_user+0x124>
lea    0xde4(%rip),%rdi
call   1030 <chdir@plt>
add    $0x10,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<become_user>:
push   %r14
push   %rbx
push   %rax
mov    %rsi,%r14
mov    %rdi,%rbx
mov    (%rdi),%rdi
mov    0x10(%rbx),%rsi
call   1090 <initgroups@plt>
cmp    $0xffffffff,%eax
jne    11bc <become_user+0x2c>
mov    (%rbx),%rsi
lea    0xe4b(%rip),%rdi
xor    %eax,%eax
call   1040 <perr@plt>
mov    0x10(%rbx),%rdi
call   10a0 <setegid@plt>
cmp    $0xffffffff,%eax
je     11d8 <become_user+0x48>
mov    0x10(%rbx),%rdi
call   1060 <setgid@plt>
cmp    $0xffffffff,%eax
jne    11ea <become_user+0x5a>
mov    0x10(%rbx),%rsi
lea    0xe3d(%rip),%rdi
xor    %eax,%eax
call   1040 <perr@plt>
xor    %eax,%eax
call   1050 <setsid@plt>
cmp    $0xffffffff,%eax
jne    1204 <become_user+0x74>
lea    0xe46(%rip),%rdi
xor    %eax,%eax
call   1040 <perr@plt>
mov    (%rbx),%rdi
call   1080 <setlogin@plt>
cmp    $0xffffffff,%eax
jne    1222 <become_user+0x92>
mov    (%rbx),%rsi
lea    0xe40(%rip),%rdi
xor    %eax,%eax
call   1040 <perr@plt>
mov    %r14,%rdi
call   1070 <setuid@plt>
cmp    $0xffffffff,%eax
je     123c <become_user+0xac>
mov    %r14,%rdi
call   10b0 <seteuid@plt>
cmp    $0xffffffff,%eax
jne    124d <become_user+0xbd>
lea    0xe36(%rip),%rdi
mov    %r14,%rsi
xor    %eax,%eax
call   1040 <perr@plt>
mov    0x8(%rbx),%rdi
call   1030 <chdir@plt>
cmp    $0xffffffff,%eax
je     1263 <become_user+0xd3>
add    $0x8,%rsp
pop    %rbx
pop    %r14
ret
lea    0xe29(%rip),%rdi
add    $0x8,%rsp
pop    %rbx
pop    %r14
jmp    1030 <chdir@plt>

LLVM IR (-O0):
%struct.passwd = type { i64, i8*, i64 }
@.str = [32 x i8] c"Cannot init group list for `%s'\00"
@.str.1 = [35 x i8] c"Cannot change primary group to %lu\00"
@.str.2 = [24 x i8] c"Cannot create a session\00"
@.str.3 = [30 x i8] c"Cannot set login name to `%s'\00"
@.str.4 = [26 x i8] c"Cannot set user id to %lu\00"
@.str.5 = [2 x i8] c"/\00"
define void @become_user(%struct.passwd* %0, i64 %1) {
%3 = alloca %struct.passwd*
%4 = alloca i64
store %struct.passwd* %0, %struct.passwd** %3
store i64 %1, i64* %4
%5 = load %struct.passwd*, %struct.passwd** %3
%6 = getelementptr inbounds %struct.passwd, %struct.passwd* %5, i32 0, i32 0
%7 = load i64, i64* %6
%8 = load %struct.passwd*, %struct.passwd** %3
%9 = getelementptr inbounds %struct.passwd, %struct.passwd* %8, i32 0, i32 2
%10 = load i64, i64* %9
%11 = call i32 @initgroups(i64 %7, i64 %10)
%12 = icmp eq i32 %11, -1
br i1 %12, label %13, label %18
13: ; preds = %2
%14 = load %struct.passwd*, %struct.passwd** %3
%15 = getelementptr inbounds %struct.passwd, %struct.passwd* %14, i32 0, i32 0
%16 = load i64, i64* %15
%17 = call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @.str, i64 0, i64 0), i64 %16)
br label %18
18: ; preds = %13, %2
%19 = load %struct.passwd*, %struct.passwd** %3
%20 = getelementptr inbounds %struct.passwd, %struct.passwd* %19, i32 0, i32 2
%21 = load i64, i64* %20
%22 = call i32 @setegid(i64 %21)
%23 = icmp eq i32 %22, -1
br i1 %23, label %30, label %24
24: ; preds = %18
%25 = load %struct.passwd*, %struct.passwd** %3
%26 = getelementptr inbounds %struct.passwd, %struct.passwd* %25, i32 0, i32 2
%27 = load i64, i64* %26
%28 = call i32 @setgid(i64 %27)
%29 = icmp eq i32 %28, -1
br i1 %29, label %30, label %35
30: ; preds = %24, %18
%31 = load %struct.passwd*, %struct.passwd** %3
%32 = getelementptr inbounds %struct.passwd, %struct.passwd* %31, i32 0, i32 2
%33 = load i64, i64* %32
%34 = call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([35 x i8], [35 x i8]* @.str.1, i64 0, i64 0), i64 %33)
br label %35
35: ; preds = %30, %24
%36 = call i32 (...) @setsid()
%37 = icmp eq i32 %36, -1
br i1 %37, label %38, label %40
38: ; preds = %35
%39 = call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str.2, i64 0, i64 0))
br label %40
40: ; preds = %38, %35
%41 = load %struct.passwd*, %struct.passwd** %3
%42 = getelementptr inbounds %struct.passwd, %struct.passwd* %41, i32 0, i32 0
%43 = load i64, i64* %42
%44 = call i32 @setlogin(i64 %43)
%45 = icmp eq i32 %44, -1
br i1 %45, label %46, label %51
46: ; preds = %40
%47 = load %struct.passwd*, %struct.passwd** %3
%48 = getelementptr inbounds %struct.passwd, %struct.passwd* %47, i32 0, i32 0
%49 = load i64, i64* %48
%50 = call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @.str.3, i64 0, i64 0), i64 %49)
br label %51
51: ; preds = %46, %40
%52 = load i64, i64* %4
%53 = call i32 @setuid(i64 %52)
%54 = icmp eq i32 %53, -1
br i1 %54, label %59, label %55
55: ; preds = %51
%56 = load i64, i64* %4
%57 = call i32 @seteuid(i64 %56)
%58 = icmp eq i32 %57, -1
br i1 %58, label %59, label %62
59: ; preds = %55, %51
%60 = load i64, i64* %4
%61 = call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.4, i64 0, i64 0), i64 %60)
br label %62
62: ; preds = %59, %55
%63 = load %struct.passwd*, %struct.passwd** %3
%64 = getelementptr inbounds %struct.passwd, %struct.passwd* %63, i32 0, i32 1
%65 = load i8*, i8** %64
%66 = call i32 @chdir(i8* %65)
%67 = icmp eq i32 %66, -1
br i1 %67, label %68, label %70
68: ; preds = %62
%69 = call i32 @chdir(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i64 0, i64 0))
br label %70
70: ; preds = %68, %62
ret void
}

LLVM IR (-O2):
%struct.passwd = type { i64, i8*, i64 }
@.str = [32 x i8] c"Cannot init group list for `%s'\00"
@.str.1 = [35 x i8] c"Cannot change primary group to %lu\00"
@.str.2 = [24 x i8] c"Cannot create a session\00"
@.str.3 = [30 x i8] c"Cannot set login name to `%s'\00"
@.str.4 = [26 x i8] c"Cannot set user id to %lu\00"
@.str.5 = [2 x i8] c"/\00"
define void @become_user(%struct.passwd* nocapture %0, i64 %1) {
%3 = getelementptr inbounds %struct.passwd, %struct.passwd* %0, i64 0, i32 0
%4 = load i64, i64* %3
%5 = getelementptr inbounds %struct.passwd, %struct.passwd* %0, i64 0, i32 2
%6 = load i64, i64* %5
%7 = tail call i32 @initgroups(i64 %4, i64 %6)
%8 = icmp eq i32 %7, -1
br i1 %8, label %9, label %12
9: ; preds = %2
%10 = load i64, i64* %3
%11 = tail call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @.str, i64 0, i64 0), i64 %10)
br label %12
12: ; preds = %9, %2
%13 = load i64, i64* %5
%14 = tail call i32 @setegid(i64 %13)
%15 = icmp eq i32 %14, -1
br i1 %15, label %20, label %16
16: ; preds = %12
%17 = load i64, i64* %5
%18 = tail call i32 @setgid(i64 %17)
%19 = icmp eq i32 %18, -1
br i1 %19, label %20, label %23
20: ; preds = %16, %12
%21 = load i64, i64* %5
%22 = tail call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([35 x i8], [35 x i8]* @.str.1, i64 0, i64 0), i64 %21)
br label %23
23: ; preds = %20, %16
%24 = tail call i32 (...) @setsid()
%25 = icmp eq i32 %24, -1
br i1 %25, label %26, label %28
26: ; preds = %23
%27 = tail call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str.2, i64 0, i64 0))
br label %28
28: ; preds = %26, %23
%29 = load i64, i64* %3
%30 = tail call i32 @setlogin(i64 %29)
%31 = icmp eq i32 %30, -1
br i1 %31, label %32, label %35
32: ; preds = %28
%33 = load i64, i64* %3
%34 = tail call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @.str.3, i64 0, i64 0), i64 %33)
br label %35
35: ; preds = %32, %28
%36 = tail call i32 @setuid(i64 %1)
%37 = icmp eq i32 %36, -1
br i1 %37, label %41, label %38
38: ; preds = %35
%39 = tail call i32 @seteuid(i64 %1)
%40 = icmp eq i32 %39, -1
br i1 %40, label %41, label %43
41: ; preds = %38, %35
%42 = tail call i32 (i8*, ...) @perr(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.4, i64 0, i64 0), i64 %1)
br label %43
43: ; preds = %41, %38
%44 = getelementptr inbounds %struct.passwd, %struct.passwd* %0, i64 0, i32 1
%45 = load i8*, i8** %44
%46 = tail call i32 @chdir(i8* %45)
%47 = icmp eq i32 %46, -1
br i1 %47, label %48, label %50
48: ; preds = %43
%49 = tail call i32 @chdir(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i64 0, i64 0))
br label %50
50: ; preds = %48, %43
ret void
}