~siretart/cryptsetup/debian

« back to all changes in this revision

Viewing changes to debian/askpass.c

  • Committer: Reinhard Tartler
  • Date: 2008-08-06 13:15:04 UTC
  • Revision ID: siretart@tauware.de-20080806131504-lm6wr3syvblxmm4b
import cryptsetup_1.0.6-3.dsc

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
 
23
23
#define _GNU_SOURCE
 
24
#define _BSD_SOURCE
 
25
#define _POSIX_C_SOURCE 1
24
26
#include <stdio.h>
25
27
#include <unistd.h>
26
28
#include <sys/types.h>
36
38
#include <sys/select.h>
37
39
#include <sys/ioctl.h>
38
40
#include <signal.h>
 
41
#include <dirent.h>
 
42
#include <linux/vt.h>
39
43
 
40
44
#define DEBUG 0
41
45
 
139
143
 *****************************************************************************/
140
144
#define USPLASH_WRITE_FIFO "/dev/.initramfs/usplash_fifo"
141
145
#define USPLASH_READ_FIFO "/dev/.initramfs/usplash_outfifo"
142
 
#define USPLASH_CONSOLE "/dev/tty8"
143
146
static size_t usplashused = 0;
144
147
static size_t usplashsize = 0;
145
148
static char *usplashbuf = NULL;
146
149
static bool usplashwaiting = false;
147
150
 
 
151
static bool
 
152
usplash_command(const char *cmd)
 
153
{
 
154
        int wrfd;
 
155
        ssize_t len;
 
156
        size_t towrite = strlen(cmd) + 1;
 
157
        size_t written = 0;
 
158
 
 
159
        wrfd = open(USPLASH_WRITE_FIFO, O_WRONLY | O_NONBLOCK);
 
160
        if (wrfd < 0)
 
161
                return false;
 
162
 
 
163
        while (written < towrite) {
 
164
                len = write(wrfd, cmd + written, towrite - written);
 
165
                if (len <= 0)
 
166
                        break;
 
167
                written += len;
 
168
        }
 
169
 
 
170
        close(wrfd);
 
171
        if (written != towrite)
 
172
                return false;
 
173
        else
 
174
                return true;
 
175
}
 
176
 
 
177
static pid_t *
 
178
pidlist(const char *target, size_t *retlen)
 
179
{
 
180
        pid_t *plist = NULL;
 
181
        size_t plistlen = 0;
 
182
        pid_t pid;
 
183
        DIR *pdir;
 
184
        FILE *fp;
 
185
        struct dirent *d;
 
186
        char path[256];
 
187
        char buf[256];
 
188
        char *tmp;
 
189
 
 
190
        pdir = opendir("/proc");
 
191
        if (!pdir)
 
192
                goto out;
 
193
 
 
194
        while ((d = readdir(pdir)) != NULL) {
 
195
                pid = (pid_t)atoi(d->d_name);
 
196
                if (!pid)
 
197
                        continue;
 
198
 
 
199
                snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name);
 
200
 
 
201
                fp = fopen(path, "r");
 
202
                if (!fp)
 
203
                        continue;
 
204
 
 
205
                tmp = fgets(buf, sizeof(buf), fp);
 
206
                fclose(fp);
 
207
                if (!tmp)
 
208
                        continue;
 
209
 
 
210
                tmp = strrchr(buf, '/');
 
211
                if (tmp)
 
212
                        tmp++;
 
213
                else
 
214
                        tmp = buf;
 
215
 
 
216
                if (strcmp(tmp, target))
 
217
                        continue;
 
218
 
 
219
                plistlen++;
 
220
                plist = realloc(plist, plistlen * sizeof(pid_t));
 
221
                if (!plist) {
 
222
                        debug("realloc failed");
 
223
                        plistlen = 0;
 
224
                        plist = NULL;
 
225
                        goto out;
 
226
                }
 
227
 
 
228
                plist[plistlen - 1] = pid;
 
229
        }
 
230
 
 
231
out:
 
232
        if (pdir)
 
233
                closedir(pdir);
 
234
        *retlen = plistlen;
 
235
        return plist;
 
236
}
 
237
 
 
238
static bool
 
239
chvt(int vtnum)
 
240
{
 
241
        int fd;
 
242
        bool rv = false;
 
243
 
 
244
        fd = open("/dev/console", O_RDWR);
 
245
        if (fd < 0)
 
246
                goto out;
 
247
 
 
248
        if (ioctl(fd, VT_ACTIVATE, vtnum))
 
249
                goto out;
 
250
 
 
251
        if (ioctl(fd, VT_WAITACTIVE, vtnum))
 
252
                goto out;
 
253
 
 
254
        rv = true;
 
255
out:
 
256
        if (fd >= 0)
 
257
                close(fd);
 
258
        return rv;
 
259
}
 
260
 
 
261
static size_t
 
262
killall(pid_t *plist, size_t plistlen, int sig)
 
263
{
 
264
        pid_t pid;
 
265
        int i;
 
266
        size_t signalled = 0;
 
267
 
 
268
        for (i = 0; i < plistlen; i++) {
 
269
                pid = plist[i];
 
270
                if (pid == 0)
 
271
                        continue;
 
272
 
 
273
                debug("Signalling %i\n", (int)pid);
 
274
                if (kill(pid, sig) == 0)
 
275
                        signalled++;
 
276
                else
 
277
                        plist[i] = 0;
 
278
        }
 
279
 
 
280
        return signalled;
 
281
}
 
282
 
148
283
static void
149
284
usplash_finish(int fd)
150
285
{
151
 
        int console;
152
 
        char buf[100];
153
 
        ssize_t ret;
154
 
        int tries = 0;
155
 
        bool somedata = false;
 
286
        pid_t *plist;
 
287
        size_t plistlen;
156
288
 
 
289
        debug("usplash_finish\n");
157
290
        if (usplashwaiting) {
158
291
                /* This is ugly, but we need to unwedge usplash if a different
159
292
                 * method has been used to provide the passphrase and usplash
160
 
                 * is still waiting for user input
 
293
                 * is still waiting for user input. Sending a newline to
 
294
                 * usplash's console did not seem to provide a reliable
 
295
                 * method and this should only be needed in exceptional
 
296
                 * cases anyway.
161
297
                 */
162
 
                debug("Usplash cleanup fd %i\n", fd);
163
 
                console = open(USPLASH_CONSOLE, O_RDWR);
164
 
                if (console >= 0) {
165
 
                        /* Send newline to usplash */
166
 
                        ioctl(console, TIOCSTI, "\n");
167
 
                        close(console);
168
 
 
169
 
                        /* Flush (partial) passphrase from pipe */
170
 
                        while (tries < 10) {
171
 
                                ret = read(fd, buf, sizeof(buf));
172
 
 
173
 
                                if (ret > 0) {
174
 
                                        somedata = true;
175
 
                                        continue;
176
 
                                }
177
 
 
178
 
                                if (ret < 0 && errno == EINTR)
179
 
                                        continue;
180
 
 
181
 
                                if ((ret <  0 && errno == EAGAIN) ||
182
 
                                    (ret == 0 && somedata == false)) {
183
 
                                        sleep(1);
184
 
                                        tries++;
185
 
                                        continue;
186
 
                                }
187
 
 
188
 
                                break;
 
298
                debug("Unwedging usplash\n");
 
299
                /* Changing the VT will normally terminate usplash */
 
300
                chvt(1);
 
301
                sleep(1);
 
302
 
 
303
                /* Get a list of remaining usplash procs (if any) to kill */
 
304
                plist = pidlist("usplash", &plistlen);
 
305
                if (plistlen > 0) {
 
306
                        if (killall(plist, plistlen, SIGTERM) > 0) {
 
307
                                sleep(2);
 
308
                                killall(plist, plistlen, SIGKILL);
189
309
                        }
190
 
                        memset(buf, '\0', sizeof(buf));
191
310
                }
192
311
                usplashwaiting = false;
 
312
        } else {
 
313
                usplash_command("TIMEOUT 15");
193
314
        }
194
315
 
195
316
        fifo_common_finish(fd, &usplashbuf, &usplashused, &usplashsize);
201
322
        debug("In usplash_read\n");
202
323
        if (fifo_common_read(fd, &usplashbuf, &usplashused, &usplashsize)) {
203
324
                while (usplashused > 0 && 
204
 
                       (usplashbuf[usplashused - 1] == '\n') ||
205
 
                       (usplashbuf[usplashused - 1] == '\0')) {
 
325
                       ((usplashbuf[usplashused - 1] == '\n') ||
 
326
                        (usplashbuf[usplashused - 1] == '\0'))) {
206
327
                        usplashused--;
207
328
                        usplashbuf[usplashused] = '\0';
208
329
                        debug("Correcting usplash read length\n");
219
340
static int
220
341
usplash_prepare(const char *prompt)
221
342
{
222
 
        int wrfd = -1;
223
343
        int rdfd = -1;
224
 
        ssize_t len;
225
 
        char command[strlen(prompt) + strlen("INPUTQUIET") + 2];
226
 
 
227
 
        sprintf(command, "INPUTQUIET %s", prompt);
228
 
 
229
 
        wrfd = open(USPLASH_WRITE_FIFO, O_WRONLY | O_NONBLOCK);
230
 
        if (wrfd < 0)
231
 
                goto out;
232
 
 
233
 
        len = write(wrfd, command, strlen(command) + 1);
234
 
        if (len < 0)
235
 
                goto out;
 
344
        char cmd_input[strlen(prompt) + strlen("INPUTQUIET") + 2];
 
345
 
 
346
        if (!usplash_command("TIMEOUT 0"))
 
347
                return -1;
 
348
 
 
349
        sprintf(cmd_input, "INPUTQUIET %s", prompt);
 
350
        if (!usplash_command(cmd_input))
 
351
                return -1;
236
352
 
237
353
        rdfd = open(USPLASH_READ_FIFO, O_RDONLY | O_NONBLOCK);
238
354
        /* If usplash is enabled, disable console */
241
357
                usplashwaiting = true;
242
358
        }
243
359
 
244
 
out:
245
 
        if (wrfd >= 0)
246
 
                close(wrfd);
247
360
        return rdfd;
248
361
}
249
362
 
392
505
        int (*prepare)(const char *prompt);
393
506
        bool (*read)(int fd, char **buf, size_t *size);
394
507
        void (*finish)(int fd);
 
508
        bool active;
395
509
        bool enabled;
396
510
        int fd;
397
511
};
398
512
 
399
513
static struct method methods[] = {
400
 
        { "usplash", usplash_prepare, usplash_read, usplash_finish, true, -1 },
401
 
        { "fifo", fifo_prepare, fifo_read, fifo_finish, true, -1 },
402
 
        { "console", console_prepare, console_read, console_finish, true, -1 }
 
514
        { "usplash", usplash_prepare, usplash_read, usplash_finish, false, true, -1 },
 
515
        { "fifo", fifo_prepare, fifo_read, fifo_finish, false, true, -1 },
 
516
        { "console", console_prepare, console_read, console_finish, false, true, -1 }
403
517
};
404
518
 
405
519
static bool
408
522
        int i;
409
523
        bool result = false;
410
524
 
 
525
        debug("Disabling method %s\n", method ? method : "ALL");
 
526
 
411
527
        for (i = 0; i < ARRAY_SIZE(methods); i++) {
 
528
                /* A NULL method means all methods should be disabled */
412
529
                if (method && strcmp(methods[i].name, method))
413
530
                        continue;
414
531
                if (!methods[i].enabled)
415
532
                        continue;
 
533
                if (methods[i].active)
 
534
                        methods[i].finish(methods[i].fd);
416
535
 
417
 
                methods[i].finish(methods[i].fd);
 
536
                methods[i].active = false;
418
537
                methods[i].fd = -1;
419
538
                methods[i].enabled = false;
420
539
                result = true;
447
566
                debug("Enabling method %s\n", methods[i].name);
448
567
                methods[i].fd = methods[i].prepare(argv[1]);
449
568
                if (methods[i].fd < 0)
450
 
                        methods[i].enabled = false;
 
569
                        methods[i].active = false;
 
570
                else
 
571
                        methods[i].active = true;
451
572
        }
452
573
 
453
574
        while (!done) {