summaryrefslogtreecommitdiffstats
path: root/devel/gamin/files/patch-libgamin_gam_fork.c
blob: 8ed0e222f7692cd0d1e3c5ebb479f33320c59af2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
--- libgamin/gam_fork.c.orig    2007-07-04 06:36:48.000000000 -0700
+++ libgamin/gam_fork.c 2013-02-16 20:37:31.298176973 -0800
@@ -42,6 +42,78 @@
     return NULL;
 }
 
+#ifdef RUN_AS_EUID
+/**
+ * gamin_drop_privileges
+ *
+ * Attempt to drop privileges to another user and group before forking
+ * a copy of the gam server
+ * 
+ * Return 0 in case of success or -1 in case of detected error.
+ */
+int
+gamin_drop_privileges(int to_uid, int to_gid)
+{
+    GAM_DEBUG(DEBUG_INFO, "Dropping privileges to %d:%d before forking server\n", to_uid, to_gid);
+
+    /* Get the current real user and group */
+    int from_uid = getuid();
+    int from_gid = getgid();
+
+    /* Make sure we were able to get the user and group values */
+    if ( from_uid == -1 || to_uid == -1 || from_gid == -1 || to_gid == -1 ) {
+        gam_error(DEBUG_INFO, "failed to get user or group info, unable to drop privileges\n");
+        return(-1);
+    }
+
+    /* Refuse to run setuid if it would escalate privileges */
+    if ( from_uid != 0 && to_uid == 0 )
+    {
+        gam_error(DEBUG_INFO, "refusing to escalate user privileges from=%d to=%d\n", from_uid, to_uid);
+        return(-1);
+    }
+
+    /* Refuse to run setgid if it would escalate privileges */
+    if ( from_gid != 0 && to_gid == 0 )
+    {
+        gam_error(DEBUG_INFO, "refusing to escalate group privileges from=%d to=%d\n", from_gid, to_gid);
+        return(-1);
+    }
+
+    /* Run setuid to drop privileges to the effective user */
+    if ( from_uid != to_uid ) {
+        GAM_DEBUG(DEBUG_INFO, "Attempting setuid from=%d to=%d\n", from_uid, to_uid);
+
+        /* run setuid and check for errors */
+        if (setuid(to_uid) == -1) {
+            gam_error(DEBUG_INFO, "failed to run setuid from=%d to=%d\n", from_uid, to_uid);
+            return(-1);
+        }
+    }
+    else {
+        GAM_DEBUG(DEBUG_INFO, "Already running as effective user, skipping setuid\n");
+    }
+
+    /* Run setgid to drop privileges to the effective group */
+    if ( from_gid != to_gid ) {
+        GAM_DEBUG(DEBUG_INFO, "Attempting setgid from=%d to=%d\n", from_gid, to_gid);
+
+        /* run setuid and check for errors */
+        if (setgid(to_gid) == -1) {
+            gam_error(DEBUG_INFO, "failed to run setgid from=%d to=%d\n", from_gid, to_gid);
+            return(-1);
+        }
+    }
+    else {
+        GAM_DEBUG(DEBUG_INFO, "Already running as effective group, skipping setgid\n");
+    }
+
+    GAM_DEBUG(DEBUG_INFO, "Succeeded in dropping privileges from %d:%d to %d:%d\n", from_uid, from_gid, to_uid, to_gid);
+
+    return(0);
+}
+#endif
+
 /**
  * gamin_fork_server:
  * @fam_client_id: the client ID string to use
@@ -71,6 +143,13 @@
         long open_max;
    long i;
 
+#ifdef RUN_AS_EUID
+        /* Drop privileges to the current effective uid/gid and return on failure */
+        if(gamin_drop_privileges( geteuid(), getegid() ) == -1) {
+            return(-1);
+        }
+#endif
+
         /* don't hold open fd opened from the client of the library */
    open_max = sysconf (_SC_OPEN_MAX);
    for (i = 0; i < open_max; i++)