~ubuntu-branches/ubuntu/vivid/sslh/vivid-proposed

« back to all changes in this revision

Viewing changes to common.c

  • Committer: Package Import Robot
  • Author(s): Guillaume Delacour
  • Date: 2014-08-07 00:06:06 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20140807000606-y1tg7j8i5t7d4drr
Tags: 1.16-1
* New upstream release: fix some startup problem when interfaces are not
  ready at boot time (IP_FREEBIND support when available) and can use libcap
  for transparent mode
* Enable libcap and libwrap support at build time
* Enable dpkg-buildflags: Drop hardening-wrapper Build-Depends and use
  DEB_BUILD_HARDENING instead of DEB_BUILD_MAINT_OPTIONS
* Remove old .gitignore as upstream has one too
* debian/sslh.tmpfile: Create /run/sslh for systemd as root because sslh
  write its pid before dropping privileges (Closes: #740560)
* debian/patches/disable_ip_freebind_test.diff: Remove "Can't bind address"
  upstream test because IP_FREEBIND is now enabled upstream
* debian/docs: upstream README is now README.md
* debian/rules:
  + use DESTDIR in addition of PREFIX as upstream change Makefile
* Refresh debian/patches/disable_valgrind_launch.diff due to upstream
  changes
* Stop service in case of purge (to be able to remove the user too)
* Use DEB_BUILD_OPTIONS to speed the build
* debian/patches/fixed_version.diff: Fix the version of binaries based on
  debian/changelog (instead of relying on git)
* Update Description as sslh is not only a ssl/ssh multiplexer but a
  protocol multiplexer

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
#include <stdarg.h>
9
9
 
10
10
#include "common.h"
 
11
#include "probe.h"
11
12
 
12
13
/* Added to make the code compilable under CYGWIN 
13
14
 * */
36
37
int allow_severity =0, deny_severity = 0;
37
38
#endif
38
39
 
39
 
 
40
40
/* check result and die, printing the offending address and error */
41
41
void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall)
42
42
{
61
61
{
62
62
   struct sockaddr_storage *saddr;
63
63
   struct addrinfo *addr;
64
 
   int i, res, reuse;
 
64
   int i, res, one;
65
65
   int num_addr = 0;
66
66
 
67
67
   for (addr = addr_list; addr; addr = addr->ai_next)
82
82
       (*sockfd)[i] = socket(saddr->ss_family, SOCK_STREAM, 0);
83
83
       check_res_dumpdie((*sockfd)[i], addr, "socket");
84
84
 
85
 
       reuse = 1;
86
 
       res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
87
 
       check_res_dumpdie(res, addr, "setsockopt");
 
85
       one = 1;
 
86
       res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
 
87
       check_res_dumpdie(res, addr, "setsockopt(SO_REUSEADDR)");
 
88
 
 
89
       if (IP_FREEBIND) {
 
90
           res = setsockopt((*sockfd)[i], IPPROTO_IP, IP_FREEBIND, (char*)&one, sizeof(one));
 
91
           check_res_dumpdie(res, addr, "setsockopt(IP_FREEBIND)");
 
92
       }
88
93
 
89
94
       res = bind((*sockfd)[i], addr->ai_addr, addr->ai_addrlen);
90
95
       check_res_dumpdie(res, addr, "bind");
110
115
    from.ai_addr = (struct sockaddr*)&ss;
111
116
    from.ai_addrlen = sizeof(ss);
112
117
 
 
118
    /* getpeername can fail with ENOTCONN if connection was dropped before we
 
119
     * got here */
113
120
    res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen);
114
 
    CHECK_RES_DIE(res, "getpeername");
 
121
    CHECK_RES_RETURN(res, "getpeername");
115
122
    res = setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &trans, sizeof(trans));
116
123
    CHECK_RES_DIE(res, "setsockopt");
117
124
    res = bind(fd, from.ai_addr, from.ai_addrlen);
123
130
/* Connect to first address that works and returns a file descriptor, or -1 if
124
131
 * none work. 
125
132
 * If transparent proxying is on, use fd_from peer address on external address
126
 
 * of new file descriptor.
127
 
 * cnx_name points to the name of the service (for logging) */
128
 
int connect_addr(struct addrinfo *addr, int fd_from, const char* cnx_name)
 
133
 * of new file descriptor. */
 
134
int connect_addr(struct connection *cnx, int fd_from)
129
135
{
130
136
    struct addrinfo *a;
131
137
    char buf[NI_MAXHOST];
132
138
    int fd, res;
133
139
 
134
 
    for (a = addr; a; a = a->ai_next) {
 
140
    for (a = cnx->proto->saddr; a; a = a->ai_next) {
135
141
        if (verbose) 
136
142
            fprintf(stderr, "connecting to %s family %d len %d\n", 
137
143
                    sprintaddr(buf, sizeof(buf), a),
138
144
                    a->ai_addr->sa_family, a->ai_addrlen);
139
145
        fd = socket(a->ai_family, SOCK_STREAM, 0);
140
146
        if (fd == -1) {
141
 
            log_message(LOG_ERR, "forward to %s failed:socket: %s\n", cnx_name, strerror(errno));
 
147
            log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
 
148
                        cnx->proto->description, strerror(errno));
142
149
        } else {
143
 
            if (transparent)
144
 
                bind_peer(fd, fd_from);
 
150
            if (transparent) {
 
151
                res = bind_peer(fd, fd_from);
 
152
                CHECK_RES_RETURN(res, "bind_peer");
 
153
            }
145
154
            res = connect(fd, a->ai_addr, a->ai_addrlen);
146
155
            if (res == -1) {
147
156
                log_message(LOG_ERR, "forward to %s failed:connect: %s\n", 
148
 
                            cnx_name, strerror(errno));
 
157
                            cnx->proto->description, strerror(errno));
149
158
            } else {
150
159
                return fd;
151
160
            }
157
166
/* Store some data to write to the queue later */
158
167
int defer_write(struct queue *q, void* data, int data_size) 
159
168
{
 
169
    char *p;
160
170
    if (verbose) 
161
 
        fprintf(stderr, "**** writing defered on fd %d\n", q->fd);
162
 
    q->defered_data = malloc(data_size);
163
 
    q->begin_defered_data = q->defered_data;
164
 
    q->defered_data_size = data_size;
165
 
    memcpy(q->defered_data, data, data_size);
 
171
        fprintf(stderr, "**** writing deferred on fd %d\n", q->fd);
 
172
 
 
173
    p = realloc(q->begin_deferred_data, q->deferred_data_size + data_size);
 
174
    if (!p) {
 
175
        perror("realloc");
 
176
        exit(1);
 
177
    }
 
178
 
 
179
    q->deferred_data = q->begin_deferred_data = p;
 
180
    p += q->deferred_data_size;
 
181
    q->deferred_data_size += data_size;
 
182
    memcpy(p, data, data_size);
166
183
 
167
184
    return 0;
168
185
}
171
188
 * Upon success, the number of bytes written is returned.
172
189
 * Upon failure, -1 returned (e.g. connexion closed)
173
190
 * */
174
 
int flush_defered(struct queue *q)
 
191
int flush_deferred(struct queue *q)
175
192
{
176
193
    int n;
177
194
 
178
195
    if (verbose)
179
 
        fprintf(stderr, "flushing defered data to fd %d\n", q->fd);
 
196
        fprintf(stderr, "flushing deferred data to fd %d\n", q->fd);
180
197
 
181
 
    n = write(q->fd, q->defered_data, q->defered_data_size);
 
198
    n = write(q->fd, q->deferred_data, q->deferred_data_size);
182
199
    if (n == -1)
183
200
        return n;
184
201
 
185
 
    if (n == q->defered_data_size) {
 
202
    if (n == q->deferred_data_size) {
186
203
        /* All has been written -- release the memory */
187
 
        free(q->begin_defered_data);
188
 
        q->begin_defered_data = NULL;
189
 
        q->defered_data = NULL;
190
 
        q->defered_data_size = 0;
 
204
        free(q->begin_deferred_data);
 
205
        q->begin_deferred_data = NULL;
 
206
        q->deferred_data = NULL;
 
207
        q->deferred_data_size = 0;
191
208
    } else {
192
209
        /* There is data left */
193
 
        q->defered_data += n;
194
 
        q->defered_data_size -= n;
 
210
        q->deferred_data += n;
 
211
        q->deferred_data_size -= n;
195
212
    }
196
213
 
197
214
    return n;
203
220
    memset(cnx, 0, sizeof(*cnx));
204
221
    cnx->q[0].fd = -1;
205
222
    cnx->q[1].fd = -1;
 
223
    cnx->proto = get_first_protocol();
206
224
}
207
225
 
208
226
void dump_connection(struct connection *cnx)
209
227
{
210
228
    printf("state: %d\n", cnx->state);
211
 
    printf("fd %d, %d defered\n", cnx->q[0].fd, cnx->q[0].defered_data_size);
212
 
    printf("fd %d, %d defered\n", cnx->q[1].fd, cnx->q[1].defered_data_size);
 
229
    printf("fd %d, %d deferred\n", cnx->q[0].fd, cnx->q[0].deferred_data_size);
 
230
    printf("fd %d, %d deferred\n", cnx->q[1].fd, cnx->q[1].deferred_data_size);
213
231
}
214
232
 
215
233
 
216
234
/* 
217
235
 * moves data from one fd to other
218
236
 *
219
 
 * retuns number of bytes copied if success
 
237
 * returns number of bytes copied if success
220
238
 * returns 0 (FD_CNXCLOSED) if incoming socket closed
221
239
 * returns FD_NODATA if no data was available
222
240
 * returns FD_STALLED if data was read, could not be written, and has been
251
269
 
252
270
   size_w = write(target, buffer, size_r);
253
271
   /* process -1 when we know how to deal with it */
254
 
   if ((size_w == -1)) {
 
272
   if (size_w == -1) {
255
273
       switch (errno) {
256
274
       case EAGAIN:
257
275
           /* write blocked: Defer data */
380
398
    addr.ai_addrlen = sizeof(ss);
381
399
 
382
400
    res = getpeername(cnx->q[0].fd, addr.ai_addr, &addr.ai_addrlen);
383
 
    if (res == -1) return; /* that should never happen, right? */
 
401
    if (res == -1) return; /* Can happen if connection drops before we get here. 
 
402
                               In that case, don't log anything (there is no connection) */
384
403
    sprintaddr(peer, sizeof(peer), &addr);
385
404
 
386
405
    addr.ai_addrlen = sizeof(ss);
421
440
    int res;
422
441
 
423
442
    res = getpeername(in_socket, &peeraddr, &size);
424
 
    CHECK_RES_DIE(res, "getpeername");
 
443
    CHECK_RES_RETURN(res, "getpeername");
425
444
 
426
445
    /* extract peer address */
427
446
    res = getnameinfo(&peeraddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
464
483
    res = sigaction(SIGCHLD, &action, NULL);
465
484
    CHECK_RES_DIE(res, "sigaction");
466
485
 
467
 
    /* Set SIGTERM to exit. For some reason if it's not set explicitely,
 
486
    /* Set SIGTERM to exit. For some reason if it's not set explicitly,
468
487
     * coverage information is lost when killing the process */
469
488
    memset(&action, 0, sizeof(action));
470
489
    action.sa_handler = exit;
482
501
 * banner is made up of basename(bin_name)+"[pid]" */
483
502
void setup_syslog(const char* bin_name) {
484
503
    char *name1, *name2;
 
504
    int res;
485
505
 
486
506
    name1 = strdup(bin_name);
487
 
    asprintf(&name2, "%s[%d]", basename(name1), getpid());
 
507
    res = asprintf(&name2, "%s[%d]", basename(name1), getpid());
 
508
    CHECK_RES_DIE(res, "asprintf");
488
509
    openlog(name2, LOG_CONS, LOG_AUTH);
489
510
    free(name1); 
490
511
    /* Don't free name2, as openlog(3) uses it (at least in glibc) */
492
513
    log_message(LOG_INFO, "%s %s started\n", server_type, VERSION);
493
514
}
494
515
 
495
 
/* We don't want to run as root -- drop priviledges if required */
 
516
/* Ask OS to keep capabilities over a setuid(nonzero) */
 
517
void set_keepcaps(int val) {
 
518
#ifdef LIBCAP
 
519
    int res;
 
520
    res = prctl(PR_SET_KEEPCAPS, val, 0, 0, 0);
 
521
    if (res) {
 
522
        perror("prctl");
 
523
        exit(1);
 
524
    }
 
525
#endif
 
526
}
 
527
 
 
528
/* set needed capabilities for effective and permitted, clear rest */
 
529
void set_capabilities(void) {
 
530
#ifdef LIBCAP
 
531
    int res;
 
532
    cap_t caps;
 
533
    cap_value_t cap_list[10];
 
534
    int ncap = 0;
 
535
 
 
536
    if (transparent)
 
537
        cap_list[ncap++] = CAP_NET_ADMIN;
 
538
 
 
539
    caps = cap_init();
 
540
 
 
541
#define _cap_set_flag(flag) do { \
 
542
        res = cap_clear_flag(caps, flag); \
 
543
        CHECK_RES_DIE(res, "cap_clear_flag(" #flag ")"); \
 
544
        if (ncap > 0) { \
 
545
            res = cap_set_flag(caps, flag, ncap, cap_list, CAP_SET); \
 
546
            CHECK_RES_DIE(res, "cap_set_flag(" #flag ")"); \
 
547
        } \
 
548
    } while(0)
 
549
 
 
550
    _cap_set_flag(CAP_EFFECTIVE);
 
551
    _cap_set_flag(CAP_PERMITTED);
 
552
 
 
553
#undef _cap_set_flag
 
554
 
 
555
    res = cap_set_proc(caps);
 
556
    CHECK_RES_DIE(res, "cap_set_proc");
 
557
 
 
558
    res = cap_free(caps);
 
559
    if (res) {
 
560
        perror("cap_free");
 
561
        exit(1);
 
562
    }
 
563
#endif
 
564
}
 
565
 
 
566
/* We don't want to run as root -- drop privileges if required */
496
567
void drop_privileges(const char* user_name)
497
568
{
498
569
    int res;
504
575
    if (verbose)
505
576
        fprintf(stderr, "turning into %s\n", user_name);
506
577
 
 
578
    set_keepcaps(1);
 
579
 
507
580
    res = setgid(pw->pw_gid);
508
581
    CHECK_RES_DIE(res, "setgid");
509
 
    setuid(pw->pw_uid);
 
582
    res = setuid(pw->pw_uid);
510
583
    CHECK_RES_DIE(res, "setuid");
 
584
 
 
585
    set_capabilities();
 
586
    set_keepcaps(0);
511
587
}
512
588
 
513
589
/* Writes my PID */