View | Details | Raw Unified | Return to bug 176203
Collapse All | Expand All

(-)Makefile (-1 / +6 lines)
Lines 27-35 Link Here
27
GNU_CONFIGURE=	yes
27
GNU_CONFIGURE=	yes
28
28
29
.if !defined(GAMIN_SLAVE)
29
.if !defined(GAMIN_SLAVE)
30
OPTIONS_DEFINE=	GAM_POLLER LIBINOTIFY 
30
OPTIONS_DEFINE=	GAM_POLLER LIBINOTIFY RUN_AS_EUID
31
GAM_POLLER_DESC=Use gamin's poller instead of kqueue's
31
GAM_POLLER_DESC=Use gamin's poller instead of kqueue's
32
LIBINOTIFY_DESC=Use libinotify as the FAM backend
32
LIBINOTIFY_DESC=Use libinotify as the FAM backend
33
RUN_AS_EUID_DESC=Drop privileges to effective user
33
.endif
34
.endif
34
35
35
.include <bsd.port.options.mk>
36
.include <bsd.port.options.mk>
Lines 48-53 Link Here
48
.endif
49
.endif
49
.endif
50
.endif
50
51
52
.if ${PORT_OPTIONS:MRUN_AS_EUID}
53
CPPFLAGS+=	-DRUN_AS_EUID=1
54
.endif
55
51
post-patch:
56
post-patch:
52
	@${REINPLACE_CMD} "s|/etc|${PREFIX}/etc|g" ${WRKSRC}/server/gam_conf.c
57
	@${REINPLACE_CMD} "s|/etc|${PREFIX}/etc|g" ${WRKSRC}/server/gam_conf.c
53
58
(-)libgamin/gam_api.c (-18 / +40 lines)
Lines 14-19 Link Here
14
#include <sys/socket.h>
14
#include <sys/socket.h>
15
#include <sys/un.h>
15
#include <sys/un.h>
16
#include <sys/uio.h>
16
#include <sys/uio.h>
17
#include <string.h>
17
#include "fam.h"
18
#include "fam.h"
18
#include "gam_protocol.h"
19
#include "gam_protocol.h"
19
#include "gam_data.h"
20
#include "gam_data.h"
Lines 117-123 Link Here
117
    if (user_name[0] != 0)
118
    if (user_name[0] != 0)
118
        return (user_name);
119
        return (user_name);
119
120
121
#ifdef RUN_AS_EUID
122
    pw = getpwuid(geteuid());
123
#else
120
    pw = getpwuid(getuid());
124
    pw = getpwuid(getuid());
125
#endif
121
126
122
    if (pw != NULL) {
127
    if (pw != NULL) {
123
	strncpy(user_name, pw->pw_name, 99);
128
	strncpy(user_name, pw->pw_name, 99);
Lines 224-230 Link Here
224
	free(dir);
229
	free(dir);
225
	return(0);
230
	return(0);
226
    }
231
    }
232
#ifdef RUN_AS_EUID
233
    if (st.st_uid != geteuid()) {
234
#else
227
    if (st.st_uid != getuid()) {
235
    if (st.st_uid != getuid()) {
236
#endif
228
	gam_error(DEBUG_INFO,
237
	gam_error(DEBUG_INFO,
229
		  "Socket directory %s has different owner\n",
238
		  "Socket directory %s has different owner\n",
230
		  dir);
239
		  dir);
Lines 301-307 Link Here
301
    if (ret < 0)
310
    if (ret < 0)
302
	return(0);
311
	return(0);
303
    
312
    
313
#ifdef RUN_AS_EUID
314
    if (st.st_uid != geteuid()) {
315
#else
304
    if (st.st_uid != getuid()) {
316
    if (st.st_uid != getuid()) {
317
#endif
305
	gam_error(DEBUG_INFO,
318
	gam_error(DEBUG_INFO,
306
		  "Socket %s has different owner\n",
319
		  "Socket %s has different owner\n",
307
		  path);
320
		  path);
Lines 428-437 Link Here
428
{
441
{
429
    char data[2] = { 0, 0 };
442
    char data[2] = { 0, 0 };
430
    int written;
443
    int written;
431
#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
444
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
432
    struct {
445
    union {
433
	    struct cmsghdr hdr;
446
	    struct cmsghdr hdr;
434
	    struct cmsgcred cred;
447
	    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
435
    } cmsg;
448
    } cmsg;
436
    struct iovec iov;
449
    struct iovec iov;
437
    struct msghdr msg;
450
    struct msghdr msg;
Lines 443-458 Link Here
443
    msg.msg_iov = &iov;
456
    msg.msg_iov = &iov;
444
    msg.msg_iovlen = 1;
457
    msg.msg_iovlen = 1;
445
458
446
    msg.msg_control = &cmsg;
459
    msg.msg_control = (caddr_t) &cmsg;
447
    msg.msg_controllen = sizeof (cmsg);
460
    msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
448
    memset (&cmsg, 0, sizeof (cmsg));
461
    memset (&cmsg, 0, sizeof (cmsg));
449
    cmsg.hdr.cmsg_len = sizeof (cmsg);
462
    cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
450
    cmsg.hdr.cmsg_level = SOL_SOCKET;
463
    cmsg.hdr.cmsg_level = SOL_SOCKET;
451
    cmsg.hdr.cmsg_type = SCM_CREDS;
464
    cmsg.hdr.cmsg_type = SCM_CREDS;
452
#endif
465
#endif
453
466
454
retry:
467
retry:
455
#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
468
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
456
    written = sendmsg(fd, &msg, 0);
469
    written = sendmsg(fd, &msg, 0);
457
#else
470
#else
458
    written = write(fd, &data[0], 1);
471
    written = write(fd, &data[0], 1);
Lines 654-668 Link Here
654
    gid_t c_gid;
667
    gid_t c_gid;
655
668
656
#ifdef HAVE_CMSGCRED
669
#ifdef HAVE_CMSGCRED
657
    struct {
670
    struct cmsgcred *cred;
671
    union {
658
	    struct cmsghdr hdr;
672
	    struct cmsghdr hdr;
659
	    struct cmsgcred cred;
673
	    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
660
    } cmsg;
674
    } cmsg;
661
#endif
675
#endif
662
676
677
#ifdef RUN_AS_EUID
678
    s_uid = geteuid();
679
#else
663
    s_uid = getuid();
680
    s_uid = getuid();
681
#endif
664
682
665
#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
683
#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED) && !defined(__FreeBSD__)
666
    /* Set the socket to receive credentials on the next message */
684
    /* Set the socket to receive credentials on the next message */
667
    {
685
    {
668
        int on = 1;
686
        int on = 1;
Lines 683-690 Link Here
683
701
684
#ifdef HAVE_CMSGCRED
702
#ifdef HAVE_CMSGCRED
685
    memset(&cmsg, 0, sizeof(cmsg));
703
    memset(&cmsg, 0, sizeof(cmsg));
686
    msg.msg_control = &cmsg;
704
    msg.msg_control = (caddr_t) &cmsg;
687
    msg.msg_controllen = sizeof(cmsg);
705
    msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
688
#endif
706
#endif
689
707
690
retry:
708
retry:
Lines 701-707 Link Here
701
        goto failed;
719
        goto failed;
702
    }
720
    }
703
#ifdef HAVE_CMSGCRED
721
#ifdef HAVE_CMSGCRED
704
    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
722
    if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) || cmsg.hdr.cmsg_type != SCM_CREDS) {
705
        GAM_DEBUG(DEBUG_INFO,
723
        GAM_DEBUG(DEBUG_INFO,
706
                  "Message from recvmsg() was not SCM_CREDS\n");
724
                  "Message from recvmsg() was not SCM_CREDS\n");
707
        goto failed;
725
        goto failed;
Lines 727-735 Link Here
727
            goto failed;
745
            goto failed;
728
        }
746
        }
729
#elif defined(HAVE_CMSGCRED)
747
#elif defined(HAVE_CMSGCRED)
730
        c_pid = cmsg.cred.cmcred_pid;
748
        cred = (struct cmsgcred *) CMSG_DATA (&cmsg);
731
        c_uid = cmsg.cred.cmcred_euid;
749
        c_pid = cred->cmcred_pid;
732
        c_gid = cmsg.cred.cmcred_groups[0];
750
        c_uid = cred->cmcred_euid;
751
        c_gid = cred->cmcred_groups[0];
733
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
752
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
734
        GAM_DEBUG(DEBUG_INFO,
753
        GAM_DEBUG(DEBUG_INFO,
735
                  "Socket credentials not supported on this OS\n");
754
                  "Socket credentials not supported on this OS\n");
Lines 1288-1301 Link Here
1288
1307
1289
    // FIXME: drop and reacquire lock while blocked?
1308
    // FIXME: drop and reacquire lock while blocked?
1290
    gamin_data_lock(conn);
1309
    gamin_data_lock(conn);
1291
    if (!gamin_data_event_ready(conn)) {
1310
    while ((ret = gamin_data_event_ready(conn)) == 0) {
1292
        if (gamin_read_data(conn, fc->fd, 1) < 0) {
1311
        if (gamin_read_data(conn, fc->fd, 1) < 0) {
1293
	    gamin_try_reconnect(conn, fc->fd);
1312
	    gamin_try_reconnect(conn, fc->fd);
1294
	    FAMErrno = FAM_CONNECT;
1313
	    FAMErrno = FAM_CONNECT;
1295
	    return (-1);
1314
	    return (-1);
1296
	}
1315
	}
1297
    }
1316
    }
1298
    ret = gamin_data_read_event(conn, fe);
1317
1318
    if (ret > 0)
1319
        ret = gamin_data_read_event(conn, fe);
1320
1299
    gamin_data_unlock(conn);
1321
    gamin_data_unlock(conn);
1300
1322
1301
    if (ret < 0) {
1323
    if (ret < 0) {
(-)libgamin/gam_fork.c (+84 lines)
Lines 42-47 Link Here
42
    return NULL;
42
    return NULL;
43
}
43
}
44
44
45
#ifdef RUN_AS_EUID
46
/**
47
 * gamin_drop_privileges
48
 *
49
 * Attempt to drop privileges to the effective uid and gid before
50
 * forking a copy of the gamin server
51
 * 
52
 * Return 0 in case of success or -1 in case of detected error.
53
 */
54
int
55
gamin_drop_privileges(void)
56
{
57
    GAM_DEBUG(DEBUG_INFO, "Dropping privileges to effective user and group\n");
58
59
    /* get the current real user and group */
60
    int from_uid = getuid();
61
    int from_gid = getgid();
62
63
    /* get the effective user and group */
64
    int to_uid = geteuid();
65
    int to_gid = getegid();
66
67
    /* make sure we were able to get the user and group values */
68
    if ( from_uid == -1 || to_uid == -1 || from_gid == -1 || to_gid == -1 ) {
69
        gam_error(DEBUG_INFO, "failed to get user or group info, unable to drop privileges\n");
70
        return(-1);
71
    }
72
73
    /* refuse to run setuid if it would escalate privileges */
74
    if ( from_uid != 0 && to_uid == 0 )
75
    {
76
        gam_error(DEBUG_INFO, "refusing to escalate user privileges from=%d to=%d\n", from_uid, to_uid);
77
        return(-1);
78
    }
79
80
    /* refuse to run setgid if it would escalate privileges */
81
    if ( from_gid != 0 && to_gid == 0 )
82
    {
83
        gam_error(DEBUG_INFO, "refusing to escalate group privileges from=%d to=%d\n", from_gid, to_gid);
84
        return(-1);
85
    }
86
87
    /* run setuid to drop privileges to the effective user */
88
    if ( from_uid != to_uid ) {
89
        GAM_DEBUG(DEBUG_INFO, "Attempting setuid from=%d to=%d\n", from_uid, to_uid);
90
91
        /* run setuid and check for errors */
92
        if (setuid(to_uid) == -1) {
93
            gam_error(DEBUG_INFO, "failed to run setuid from=%d to=%d\n", from_uid, to_uid);
94
            return(-1);
95
        }
96
    }
97
    else {
98
        GAM_DEBUG(DEBUG_INFO, "Already running as effective user, skipping setuid\n");
99
    }
100
101
    /* run setgid to drop privileges to the effective group */
102
    if ( from_gid != to_gid ) {
103
        GAM_DEBUG(DEBUG_INFO, "Attempting setgid from=%d to=%d\n", from_gid, to_gid);
104
105
        /* run setuid and check for errors */
106
        if (setgid(to_gid) == -1) {
107
            gam_error(DEBUG_INFO, "failed to run setgid from=%d to=%d\n", from_uid, to_uid);
108
            return(-1);
109
        }
110
    }
111
    else {
112
        GAM_DEBUG(DEBUG_INFO, "Already running as effective group, skipping setgid\n");
113
    }
114
115
    GAM_DEBUG(DEBUG_INFO, "Succeeded in dropping privileges from %d:%d to %d:%d\n", from_uid, from_gid, to_uid, to_gid);
116
117
    return(0);
118
}
119
#endif
120
45
/**
121
/**
46
 * gamin_fork_server:
122
 * gamin_fork_server:
47
 * @fam_client_id: the client ID string to use
123
 * @fam_client_id: the client ID string to use
Lines 71-76 Link Here
71
        long open_max;
147
        long open_max;
72
	long i;
148
	long i;
73
149
150
#ifdef RUN_AS_EUID
151
        /* Drop privileges to the current uid/gid and return on failure */
152
        if(gamin_drop_privileges() == -1)
153
        {
154
            return(-1);
155
        }
156
#endif
157
74
        /* don't hold open fd opened from the client of the library */
158
        /* don't hold open fd opened from the client of the library */
75
	open_max = sysconf (_SC_OPEN_MAX);
159
	open_max = sysconf (_SC_OPEN_MAX);
76
	for (i = 0; i < open_max; i++)
160
	for (i = 0; i < open_max; i++)
(-)libgamin/gam_api.c (-18 / +40 lines)
Lines 14-19 Link Here
14
#include <sys/socket.h>
14
#include <sys/socket.h>
15
#include <sys/un.h>
15
#include <sys/un.h>
16
#include <sys/uio.h>
16
#include <sys/uio.h>
17
#include <string.h>
17
#include "fam.h"
18
#include "fam.h"
18
#include "gam_protocol.h"
19
#include "gam_protocol.h"
19
#include "gam_data.h"
20
#include "gam_data.h"
Lines 117-123 Link Here
117
    if (user_name[0] != 0)
118
    if (user_name[0] != 0)
118
        return (user_name);
119
        return (user_name);
119
120
121
#ifdef RUN_AS_EUID
122
    pw = getpwuid(geteuid());
123
#else
120
    pw = getpwuid(getuid());
124
    pw = getpwuid(getuid());
125
#endif
121
126
122
    if (pw != NULL) {
127
    if (pw != NULL) {
123
	strncpy(user_name, pw->pw_name, 99);
128
	strncpy(user_name, pw->pw_name, 99);
Lines 224-230 Link Here
224
	free(dir);
229
	free(dir);
225
	return(0);
230
	return(0);
226
    }
231
    }
232
#ifdef RUN_AS_EUID
233
    if (st.st_uid != geteuid()) {
234
#else
227
    if (st.st_uid != getuid()) {
235
    if (st.st_uid != getuid()) {
236
#endif
228
	gam_error(DEBUG_INFO,
237
	gam_error(DEBUG_INFO,
229
		  "Socket directory %s has different owner\n",
238
		  "Socket directory %s has different owner\n",
230
		  dir);
239
		  dir);
Lines 301-307 Link Here
301
    if (ret < 0)
310
    if (ret < 0)
302
	return(0);
311
	return(0);
303
    
312
    
313
#ifdef RUN_AS_EUID
314
    if (st.st_uid != geteuid()) {
315
#else
304
    if (st.st_uid != getuid()) {
316
    if (st.st_uid != getuid()) {
317
#endif
305
	gam_error(DEBUG_INFO,
318
	gam_error(DEBUG_INFO,
306
		  "Socket %s has different owner\n",
319
		  "Socket %s has different owner\n",
307
		  path);
320
		  path);
Lines 428-437 Link Here
428
{
441
{
429
    char data[2] = { 0, 0 };
442
    char data[2] = { 0, 0 };
430
    int written;
443
    int written;
431
#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
444
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
432
    struct {
445
    union {
433
	    struct cmsghdr hdr;
446
	    struct cmsghdr hdr;
434
	    struct cmsgcred cred;
447
	    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
435
    } cmsg;
448
    } cmsg;
436
    struct iovec iov;
449
    struct iovec iov;
437
    struct msghdr msg;
450
    struct msghdr msg;
Lines 443-458 Link Here
443
    msg.msg_iov = &iov;
456
    msg.msg_iov = &iov;
444
    msg.msg_iovlen = 1;
457
    msg.msg_iovlen = 1;
445
458
446
    msg.msg_control = &cmsg;
459
    msg.msg_control = (caddr_t) &cmsg;
447
    msg.msg_controllen = sizeof (cmsg);
460
    msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
448
    memset (&cmsg, 0, sizeof (cmsg));
461
    memset (&cmsg, 0, sizeof (cmsg));
449
    cmsg.hdr.cmsg_len = sizeof (cmsg);
462
    cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
450
    cmsg.hdr.cmsg_level = SOL_SOCKET;
463
    cmsg.hdr.cmsg_level = SOL_SOCKET;
451
    cmsg.hdr.cmsg_type = SCM_CREDS;
464
    cmsg.hdr.cmsg_type = SCM_CREDS;
452
#endif
465
#endif
453
466
454
retry:
467
retry:
455
#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
468
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
456
    written = sendmsg(fd, &msg, 0);
469
    written = sendmsg(fd, &msg, 0);
457
#else
470
#else
458
    written = write(fd, &data[0], 1);
471
    written = write(fd, &data[0], 1);
Lines 654-668 Link Here
654
    gid_t c_gid;
667
    gid_t c_gid;
655
668
656
#ifdef HAVE_CMSGCRED
669
#ifdef HAVE_CMSGCRED
657
    struct {
670
    struct cmsgcred *cred;
671
    union {
658
	    struct cmsghdr hdr;
672
	    struct cmsghdr hdr;
659
	    struct cmsgcred cred;
673
	    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
660
    } cmsg;
674
    } cmsg;
661
#endif
675
#endif
662
676
677
#ifdef RUN_AS_EUID
678
    s_uid = geteuid();
679
#else
663
    s_uid = getuid();
680
    s_uid = getuid();
681
#endif
664
682
665
#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
683
#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED) && !defined(__FreeBSD__)
666
    /* Set the socket to receive credentials on the next message */
684
    /* Set the socket to receive credentials on the next message */
667
    {
685
    {
668
        int on = 1;
686
        int on = 1;
Lines 683-690 Link Here
683
701
684
#ifdef HAVE_CMSGCRED
702
#ifdef HAVE_CMSGCRED
685
    memset(&cmsg, 0, sizeof(cmsg));
703
    memset(&cmsg, 0, sizeof(cmsg));
686
    msg.msg_control = &cmsg;
704
    msg.msg_control = (caddr_t) &cmsg;
687
    msg.msg_controllen = sizeof(cmsg);
705
    msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
688
#endif
706
#endif
689
707
690
retry:
708
retry:
Lines 701-707 Link Here
701
        goto failed;
719
        goto failed;
702
    }
720
    }
703
#ifdef HAVE_CMSGCRED
721
#ifdef HAVE_CMSGCRED
704
    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
722
    if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) || cmsg.hdr.cmsg_type != SCM_CREDS) {
705
        GAM_DEBUG(DEBUG_INFO,
723
        GAM_DEBUG(DEBUG_INFO,
706
                  "Message from recvmsg() was not SCM_CREDS\n");
724
                  "Message from recvmsg() was not SCM_CREDS\n");
707
        goto failed;
725
        goto failed;
Lines 727-735 Link Here
727
            goto failed;
745
            goto failed;
728
        }
746
        }
729
#elif defined(HAVE_CMSGCRED)
747
#elif defined(HAVE_CMSGCRED)
730
        c_pid = cmsg.cred.cmcred_pid;
748
        cred = (struct cmsgcred *) CMSG_DATA (&cmsg);
731
        c_uid = cmsg.cred.cmcred_euid;
749
        c_pid = cred->cmcred_pid;
732
        c_gid = cmsg.cred.cmcred_groups[0];
750
        c_uid = cred->cmcred_euid;
751
        c_gid = cred->cmcred_groups[0];
733
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
752
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
734
        GAM_DEBUG(DEBUG_INFO,
753
        GAM_DEBUG(DEBUG_INFO,
735
                  "Socket credentials not supported on this OS\n");
754
                  "Socket credentials not supported on this OS\n");
Lines 1288-1301 Link Here
1288
1307
1289
    // FIXME: drop and reacquire lock while blocked?
1308
    // FIXME: drop and reacquire lock while blocked?
1290
    gamin_data_lock(conn);
1309
    gamin_data_lock(conn);
1291
    if (!gamin_data_event_ready(conn)) {
1310
    while ((ret = gamin_data_event_ready(conn)) == 0) {
1292
        if (gamin_read_data(conn, fc->fd, 1) < 0) {
1311
        if (gamin_read_data(conn, fc->fd, 1) < 0) {
1293
	    gamin_try_reconnect(conn, fc->fd);
1312
	    gamin_try_reconnect(conn, fc->fd);
1294
	    FAMErrno = FAM_CONNECT;
1313
	    FAMErrno = FAM_CONNECT;
1295
	    return (-1);
1314
	    return (-1);
1296
	}
1315
	}
1297
    }
1316
    }
1298
    ret = gamin_data_read_event(conn, fe);
1317
1318
    if (ret > 0)
1319
        ret = gamin_data_read_event(conn, fe);
1320
1299
    gamin_data_unlock(conn);
1321
    gamin_data_unlock(conn);
1300
1322
1301
    if (ret < 0) {
1323
    if (ret < 0) {

Return to bug 176203