/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/askpass-fifo.c

  • Committer: Teddy Hogeborn
  • Date: 2016-03-17 20:40:55 UTC
  • mto: (237.7.594 trunk)
  • mto: This revision was merged to the branch mainline in revision 341.
  • Revision ID: teddy@recompile.se-20160317204055-bhsh5xsidq7w5cxu
Client: Fix plymouth agent; broken since 1.7.2.

Fix an very old memory bug in the plymouth agent (which has been
present since its apperance in version 1.2), but which was only
recently detected at run time due to the new -fsanitize=address
compile- time flag, which has been used since version 1.7.2.  This
detection of a memory access violation causes the program to abort,
making the Plymouth graphical boot system unable to accept interactive
input of passwords when using the Mandos client.

* plugins.d/plymouth.c (exec_and_wait): Fix memory allocation bug when
  allocating new_argv.  Also tolerate a zero-length argv.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Askpass-FIFO - Read a password from a FIFO and output it
4
4
 * 
5
 
 * Copyright © 2008,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
 
5
 * Copyright © 2008-2016 Teddy Hogeborn
 
6
 * Copyright © 2008-2016 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
19
19
 * along with this program.  If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 * 
22
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
23
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
22
 * Contact the authors at <mandos@recompile.se>.
24
23
 */
25
24
 
26
25
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
27
 
#include <sys/types.h>          /* ssize_t */
 
26
#include <sys/types.h>          /* uid_t, gid_t, ssize_t */
28
27
#include <sys/stat.h>           /* mkfifo(), S_IRUSR, S_IWUSR */
29
28
#include <iso646.h>             /* and */
30
 
#include <errno.h>              /* errno, EEXIST */
31
 
#include <stdio.h>              /* perror() */
 
29
#include <errno.h>              /* errno, EACCES, ENOTDIR, ELOOP,
 
30
                                   ENAMETOOLONG, ENOSPC, EROFS,
 
31
                                   ENOENT, EEXIST, EFAULT, EMFILE,
 
32
                                   ENFILE, ENOMEM, EBADF, EINVAL, EIO,
 
33
                                   EISDIR, EFBIG */
 
34
#include <error.h>              /* error() */
 
35
#include <stdio.h>              /* fprintf(), vfprintf(),
 
36
                                   vasprintf() */
32
37
#include <stdlib.h>             /* EXIT_FAILURE, NULL, size_t, free(),
33
38
                                   realloc(), EXIT_SUCCESS */
34
39
#include <fcntl.h>              /* open(), O_RDONLY */
35
40
#include <unistd.h>             /* read(), close(), write(),
36
41
                                   STDOUT_FILENO */
37
 
 
 
42
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
 
43
                                   EX_UNAVAILABLE, EX_IOERR */
 
44
#include <string.h>             /* strerror() */
 
45
#include <stdarg.h>             /* va_list, va_start(), ... */
 
46
 
 
47
uid_t uid = 65534;
 
48
gid_t gid = 65534;
 
49
 
 
50
/* Function to use when printing errors */
 
51
__attribute__((format (gnu_printf, 3, 4)))
 
52
void error_plus(int status, int errnum, const char *formatstring,
 
53
                ...){
 
54
  va_list ap;
 
55
  char *text;
 
56
  int ret;
 
57
  
 
58
  va_start(ap, formatstring);
 
59
  ret = vasprintf(&text, formatstring, ap);
 
60
  if(ret == -1){
 
61
    fprintf(stderr, "Mandos plugin %s: ",
 
62
            program_invocation_short_name);
 
63
    vfprintf(stderr, formatstring, ap);
 
64
    fprintf(stderr, ": ");
 
65
    fprintf(stderr, "%s\n", strerror(errnum));
 
66
    error(status, errno, "vasprintf while printing error");
 
67
    return;
 
68
  }
 
69
  fprintf(stderr, "Mandos plugin ");
 
70
  error(status, errnum, "%s", text);
 
71
  free(text);
 
72
}
38
73
 
39
74
int main(__attribute__((unused))int argc,
40
75
         __attribute__((unused))char **argv){
41
76
  int ret = 0;
42
77
  ssize_t sret;
43
78
  
 
79
  uid = getuid();
 
80
  gid = getgid();
 
81
  
44
82
  /* Create FIFO */
45
83
  const char passfifo[] = "/lib/cryptsetup/passfifo";
46
 
  ret = (int)TEMP_FAILURE_RETRY(mkfifo(passfifo, S_IRUSR | S_IWUSR));
47
 
  if(ret == -1 and errno != EEXIST){
48
 
    perror("mkfifo");
49
 
    return EXIT_FAILURE;
 
84
  ret = mkfifo(passfifo, S_IRUSR | S_IWUSR);
 
85
  if(ret == -1){
 
86
    int e = errno;
 
87
    switch(e){
 
88
    case EACCES:
 
89
    case ENOTDIR:
 
90
    case ELOOP:
 
91
      error_plus(EX_OSFILE, errno, "mkfifo");
 
92
    case ENAMETOOLONG:
 
93
    case ENOSPC:
 
94
    case EROFS:
 
95
    default:
 
96
      error_plus(EX_OSERR, errno, "mkfifo");
 
97
    case ENOENT:
 
98
      /* no "/lib/cryptsetup"? */
 
99
      error_plus(EX_UNAVAILABLE, errno, "mkfifo");
 
100
    case EEXIST:
 
101
      break;                    /* not an error */
 
102
    }
50
103
  }
51
104
  
52
105
  /* Open FIFO */
53
 
  int fifo_fd = (int)TEMP_FAILURE_RETRY(open(passfifo, O_RDONLY));
 
106
  int fifo_fd = open(passfifo, O_RDONLY);
54
107
  if(fifo_fd == -1){
55
 
    perror("open");
56
 
    return EXIT_FAILURE;
 
108
    int e = errno;
 
109
    error_plus(0, errno, "open");
 
110
    switch(e){
 
111
    case EACCES:
 
112
    case ENOENT:
 
113
    case EFAULT:
 
114
      return EX_UNAVAILABLE;
 
115
    case ENAMETOOLONG:
 
116
    case EMFILE:
 
117
    case ENFILE:
 
118
    case ENOMEM:
 
119
    default:
 
120
      return EX_OSERR;
 
121
    case ENOTDIR:
 
122
    case ELOOP:
 
123
      return EX_OSFILE;
 
124
    }
 
125
  }
 
126
  
 
127
  /* Lower group privileges  */
 
128
  if(setgid(gid) == -1){
 
129
    error_plus(0, errno, "setgid");
 
130
  }
 
131
  
 
132
  /* Lower user privileges */
 
133
  if(setuid(uid) == -1){
 
134
    error_plus(0, errno, "setuid");
57
135
  }
58
136
  
59
137
  /* Read from FIFO */
62
140
  {
63
141
    size_t buf_allocated = 0;
64
142
    const size_t blocksize = 1024;
65
 
    do{
 
143
    do {
66
144
      if(buf_len + blocksize > buf_allocated){
67
145
        char *tmp = realloc(buf, buf_allocated + blocksize);
68
146
        if(tmp == NULL){
69
 
          perror("realloc");
 
147
          error_plus(0, errno, "realloc");
70
148
          free(buf);
71
 
          return EXIT_FAILURE;
 
149
          return EX_OSERR;
72
150
        }
73
151
        buf = tmp;
74
152
        buf_allocated += blocksize;
75
153
      }
76
 
      sret = TEMP_FAILURE_RETRY(read(fifo_fd, buf + buf_len,
77
 
                                     buf_allocated - buf_len));
 
154
      sret = read(fifo_fd, buf + buf_len, buf_allocated - buf_len);
78
155
      if(sret == -1){
79
 
        perror("read");
 
156
        int e = errno;
80
157
        free(buf);
81
 
        return EXIT_FAILURE;
 
158
        errno = e;
 
159
        error_plus(0, errno, "read");
 
160
        switch(e){
 
161
        case EBADF:
 
162
        case EFAULT:
 
163
        case EINVAL:
 
164
        default:
 
165
          return EX_OSERR;
 
166
        case EIO:
 
167
          return EX_IOERR;
 
168
        case EISDIR:
 
169
          return EX_UNAVAILABLE;
 
170
        }
82
171
      }
83
172
      buf_len += (size_t)sret;
84
 
    }while(sret != 0);
 
173
    } while(sret != 0);
85
174
  }
86
175
  
87
176
  /* Close FIFO */
88
 
  TEMP_FAILURE_RETRY(close(fifo_fd));
 
177
  close(fifo_fd);
89
178
  
90
179
  /* Print password to stdout */
91
180
  size_t written = 0;
92
181
  while(written < buf_len){
93
 
    sret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf + written,
94
 
                                    buf_len - written));
 
182
    sret = write(STDOUT_FILENO, buf + written, buf_len - written);
95
183
    if(sret == -1){
96
 
      perror("write");
 
184
      int e = errno;
97
185
      free(buf);
98
 
      return EXIT_FAILURE;
 
186
      errno = e;
 
187
      error_plus(0, errno, "write");
 
188
      switch(e){
 
189
      case EBADF:
 
190
      case EFAULT:
 
191
      case EINVAL:
 
192
        return EX_OSFILE;
 
193
      case EFBIG:
 
194
      case EIO:
 
195
      case ENOSPC:
 
196
      default:
 
197
        return EX_IOERR;
 
198
      }
99
199
    }
100
200
    written += (size_t)sret;
101
201
  }
102
202
  free(buf);
103
203
  
 
204
  ret = close(STDOUT_FILENO);
 
205
  if(ret == -1){
 
206
    int e = errno;
 
207
    error_plus(0, errno, "close");
 
208
    switch(e){
 
209
    case EBADF:
 
210
      return EX_OSFILE;
 
211
    case EIO:
 
212
    default:
 
213
      return EX_IOERR;
 
214
    }
 
215
  }
104
216
  return EXIT_SUCCESS;
105
217
}