OpenDNSSEC-libhsm 2.1.10
pin.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation).
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <sys/shm.h>
32#include <sys/sem.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <string.h>
36#include <unistd.h>
37#include <termios.h>
38#include <errno.h>
39
40#include "libhsm.h"
41
43extern hsm_ctx_t *_hsm_ctx;
44
45/* Function from libhsm.c */
46void
47hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action,
48 const char *message, ...);
49
50/* Constants */
51#define SHM_KEY (key_t)0x0d50d5ec
52#define SEM_KEY (key_t)0x0d50d5ec
53#define SHM_PERM S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
54#define SEM_PERM S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
55
56#ifndef HAVE_UNION_SEMUN
57/* From man page for semctl */
58union semun {
59 int val; /* Value for SETVAL */
60 struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
61 unsigned short *array; /* Array for GETALL, SETALL */
62};
63#endif
64
65/* Remember PIN that we can save */
66static char pin[HSM_MAX_PIN_LENGTH+1];
67
68static char *
69prompt_pass(char *prompt)
70{
71 int c, i = 0;
72 static char pass[HSM_MAX_PIN_LENGTH+1];
73 struct termios oldt, newt;
74
75 if (prompt == NULL) return NULL;
76
77 printf("%s", prompt);
78
79 /* Turn echoing off */
80 if (isatty(fileno(stdin))) {
81 if (tcgetattr(fileno(stdin), &oldt) != 0) return NULL;
82 newt = oldt;
83 newt.c_lflag &= ~ECHO;
84 if (tcsetattr(fileno(stdin), TCSAFLUSH, &newt) != 0) return NULL;
85 }
86
87 /* Get the password */
88 do {
89 c = fgetc(stdin);
90 pass[i] = c;
91 i++;
92 } while (c != EOF && c != '\n' && c != '\r' && i < HSM_MAX_PIN_LENGTH+1);
93 pass[i-1] = '\0';
94
95 /* Restore echoing */
96 if (isatty(fileno(stdin))) {
97 tcsetattr(fileno(stdin), TCSAFLUSH, &oldt);
98 }
99 printf("\n");
100
101 return pass;
102}
103
104static int
105hsm_sem_open()
106{
107 int semid;
108 struct semid_ds buf;
109 union semun arg;
110
111 /* Create/get the semaphore */
112 semid = semget(SEM_KEY, 1, IPC_CREAT|IPC_EXCL|SEM_PERM);
113 if (semid == -1) {
114 semid = semget(SEM_KEY, 1, IPC_CREAT|SEM_PERM);
115 if (semid == -1) {
116 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
117 "Could not access the semaphore: %s", strerror(errno));
118 return -1;
119 }
120 } else {
121 /* Set value to 1 if we created it */
122 arg.val = 1;
123 if (semctl(semid, 0, SETVAL, arg) == -1) {
124 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
125 "Could not set value on the semaphore: %s", strerror(errno));
126 return -1;
127 }
128 }
129
130 /* Get information about the semaphore */
131 arg.buf = &buf;
132 if (semctl(semid, 0, IPC_STAT, arg) != 0) {
133 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
134 "Could not stat the semaphore: %s", strerror(errno));
135 return -1;
136 }
137
138 /* Check permission to avoid an attack */
139 if ((buf.sem_perm.mode & (SEM_PERM)) != (SEM_PERM) ||
140 buf.sem_perm.gid != getegid())
141 {
142 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
143 "Bad permissions on the semaphore, please read Getting Help/Troubleshooting on OpenDNSSEC Wiki about this.");
144 return -1;
145 }
146
147 return semid;
148}
149
150static int
151hsm_sem_wait(int semid)
152{
153 struct sembuf sb = { 0, -1, 0 };
154
155 if (semop(semid, &sb, 1) == -1) {
156 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_wait()",
157 "Could not lock the semaphore: %s", strerror(errno));
158 return -1;
159 }
160
161 return 0;
162}
163
164static int
165hsm_sem_post(int semid)
166{
167 struct sembuf sb = { 0, 1, 0 };
168
169 if (semop(semid, &sb, 1) == -1) {
170 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_post()",
171 "Could not unlock the semaphore: %s", strerror(errno));
172 return -1;
173 }
174
175 return 0;
176}
177
178static int
179hsm_shm_open()
180{
181 int shmid;
182 size_t shmsize;
183 struct shmid_ds buf;
184
185 /* Create/get the shared memory */
186 shmsize = sizeof(char)*HSM_MAX_SESSIONS*(HSM_MAX_PIN_LENGTH+1);
187 shmid = shmget(SHM_KEY, shmsize, IPC_CREAT|IPC_EXCL|SHM_PERM);
188 if (shmid == -1) {
189 shmid = shmget(SHM_KEY, shmsize, IPC_CREAT|SHM_PERM);
190 if (shmid == -1) {
191 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
192 "Could not access the shared memory: %s", strerror(errno));
193 return -1;
194 }
195 } else {
196 /* Zeroize if we created the memory area */
197
198 /* The data should be set to zero according to man page */
199 }
200
201 /* Get information about the shared memory */
202 if (shmctl(shmid, IPC_STAT, &buf) != 0) {
203 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
204 "Could not stat the semaphore: %s", strerror(errno));
205 return -1;
206 }
207
208 /* Check the size of the memory segment */
209 if ((size_t)buf.shm_segsz != shmsize) {
210 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
211 "Bad memory size, please read Getting Help/Troubleshooting on OpenDNSSEC Wiki about this.");
212 return -1;
213 }
214
215 /* Check permission to avoid an attack */
216 if ((buf.shm_perm.mode & (SHM_PERM)) != (SHM_PERM) ||
217 buf.shm_perm.gid != getegid())
218 {
219 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
220 "Bad permissions on the shared memory, please read Getting Help/Troubleshooting on OpenDNSSEC Wiki about this.");
221 return -1;
222 }
223
224 return shmid;
225}
226
227char *
228hsm_prompt_pin(unsigned int id, const char *repository, unsigned int mode)
229{
230 /* Shared memory */
231 int shmid;
232 int semid;
233 char *pins = NULL;
234 int index = id * (HSM_MAX_PIN_LENGTH + 1);
235
236 /* PIN from getpass */
237 char prompt[64];
238 char *prompt_pin = NULL;
239 unsigned int size = 0;
240
241 /* Check input data */
242 if (id >= HSM_MAX_SESSIONS) return NULL;
243 if (repository == NULL) return NULL;
244 if (mode != HSM_PIN_FIRST && mode != HSM_PIN_RETRY && mode != HSM_PIN_SAVE) return NULL;
245
246 /* Create/get the semaphore */
247 semid = hsm_sem_open();
248 if (semid == -1) return NULL;
249
250 /* Lock the semaphore */
251 if (hsm_sem_wait(semid) != 0) return NULL;
252
253 /* Create/get the shared memory */
254 shmid = hsm_shm_open();
255 if (shmid == -1) {
256 hsm_sem_post(semid);
257 return NULL;
258 }
259
260 /* Attach to the shared memory */
261 pins = (char *)shmat(shmid, NULL, 0);
262 if (pins == (char *)-1) {
263 pins = NULL;
264 hsm_sem_post(semid);
265 return NULL;
266 }
267
268 /* Get the PIN */
269 if (mode != HSM_PIN_SAVE) {
270 /* Do we have a PIN in the shared memory? */
271 if (mode == HSM_PIN_FIRST && pins[index] != '\0') {
272 size = strlen(&pins[index]);
273 if (size > HSM_MAX_PIN_LENGTH) size = HSM_MAX_PIN_LENGTH;
274 memcpy(pin, &pins[index], size);
275 pin[size] = '\0';
276 } else {
277 /* Zeroize bad PIN in shared memory */
278 if (mode == HSM_PIN_RETRY && pins[index] != '\0') {
279 memset(&pins[index], '\0', HSM_MAX_PIN_LENGTH+1);
280 }
281
282 /* Unlock the semaphore if someone would do Ctrl+C */
283 hsm_sem_post(semid);
284
285 /* Get PIN */
286 snprintf(prompt, 64, "Enter PIN for token %s: ", repository);
287 prompt_pin = prompt_pass(prompt);
288 if (prompt_pin == NULL) {
289 shmdt(pins);
290 pins = NULL;
291 return NULL;
292 }
293
294 /* Lock the semaphore */
295 hsm_sem_wait(semid);
296
297 /* Remember PIN */
298 size = strlen(prompt_pin);
299 if (size > HSM_MAX_PIN_LENGTH) size = HSM_MAX_PIN_LENGTH;
300 memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
301 memcpy(pin, prompt_pin, size);
302
303 /* Zeroize the prompt_pass PIN */
304 memset(prompt_pin, '\0', strlen(prompt_pin));
305 }
306 } else {
307 /* Save the PIN */
308 memcpy(&pins[index], pin, HSM_MAX_PIN_LENGTH+1);
309
310 /* Zeroize the PIN */
311 memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
312 }
313
314 /* Detach from the shared memory */
315 shmdt(pins);
316 pins = NULL;
317
318 /* Unlock the semaphore */
319 hsm_sem_post(semid);
320
321 return pin;
322}
323
324char *
325hsm_check_pin(unsigned int id, const char *repository, unsigned int mode)
326{
327 /* Shared memory */
328 int shmid;
329 int semid;
330 char *pins = NULL;
331 int index = id * (HSM_MAX_PIN_LENGTH + 1);
332
333 unsigned int size = 0;
334
335 /* Check input data */
336 if (id >= HSM_MAX_SESSIONS) return NULL;
337 if (repository == NULL) return NULL;
338 if (mode != HSM_PIN_FIRST && mode != HSM_PIN_RETRY && mode != HSM_PIN_SAVE) return NULL;
339 if (mode == HSM_PIN_SAVE) {
340 /* Nothing to save */
341
342 /* Zeroize the PIN */
343 memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
344
345 return pin;
346 }
347
348 /* Create/get the semaphore */
349 semid = hsm_sem_open();
350 if (semid == -1) return NULL;
351
352 /* Lock the semaphore */
353 if (hsm_sem_wait(semid) != 0) return NULL;
354
355 /* Create/get the shared memory */
356 shmid = hsm_shm_open();
357 if (shmid == -1) {
358 hsm_sem_post(semid);
359 return NULL;
360 }
361
362 /* Attach to the shared memory */
363 pins = (char *)shmat(shmid, NULL, 0);
364 if (pins == (char *)-1) {
365 pins = NULL;
366 hsm_sem_post(semid);
367 return NULL;
368 }
369
370 /* Zeroize PIN buffer */
371 memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
372
373 /* Check if there is no PIN */
374 if (pins[index] == '\0') {
375 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_check_pin()",
376 "No PIN in shared memory. "
377 "Please login with \"ods-hsmutil login\"");
378 shmdt(pins);
379 pins = NULL;
380 hsm_sem_post(semid);
381 return NULL;
382 }
383
384 /* Zeroize bad PIN in shared memory */
385 if (mode == HSM_PIN_RETRY) {
386 memset(&pins[index], '\0', HSM_MAX_PIN_LENGTH+1);
387 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_check_pin()",
388 "Removed bad PIN in shared memory. "
389 "Please login again with \"ods-hsmutil login\"");
390 shmdt(pins);
391 pins = NULL;
392 hsm_sem_post(semid);
393 return NULL;
394 }
395
396 /* Get the PIN */
397 size = strlen(&pins[index]);
398 if (size > HSM_MAX_PIN_LENGTH) size = HSM_MAX_PIN_LENGTH;
399 memcpy(pin, &pins[index], size);
400 pin[size] = '\0';
401
402 /* Detach from the shared memory */
403 shmdt(pins);
404 pins = NULL;
405
406 /* Unlock the semaphore */
407 hsm_sem_post(semid);
408
409 return pin;
410}
411
412int
414{
415 int semid;
416 int shmid;
417 union semun arg;
418 struct shmid_ds buf;
419
420 /* Get the semaphore */
421 semid = semget(SEM_KEY, 1, 0);
422 if (semid == -1) {
423 if (errno != ENOENT) {
424 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
425 "Could not access the semaphore: %s", strerror(errno));
426 return HSM_ERROR;
427 }
428 } else {
429 arg.val = 0;
430 /* Remove the semaphore */
431 if (semctl(semid, 0, IPC_RMID, arg) != 0) {
432 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
433 "Could not delete the semaphore: %s", strerror(errno));
434 return HSM_ERROR;
435 }
436 }
437
438 /* Get the shared memory */
439 shmid = shmget(SHM_KEY, 0, 0);
440 if (shmid == -1) {
441 if (errno != ENOENT) {
442 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
443 "Could not access the shared memory: %s", strerror(errno));
444 return HSM_ERROR;
445 }
446 } else {
447 /* Remove the shared memory */
448 if (shmctl(shmid, IPC_RMID, &buf) != 0) {
449 hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
450 "Could not stat the semaphore: %s", strerror(errno));
451 return HSM_ERROR;
452 }
453 }
454
455 return HSM_OK;
456}
457
hsm_ctx_t * ctx
Definition: hsmutil.c:48
#define HSM_MAX_PIN_LENGTH
Definition: libhsm.h:59
#define HSM_ERROR
Definition: libhsm.h:66
#define HSM_PIN_RETRY
Definition: libhsm.h:75
#define HSM_PIN_SAVE
Definition: libhsm.h:76
#define HSM_PIN_FIRST
Definition: libhsm.h:74
#define HSM_OK
Definition: libhsm.h:65
#define HSM_MAX_SESSIONS
Definition: libhsm.h:45
hsm_ctx_t * _hsm_ctx
Definition: libhsm.c:57
char * hsm_prompt_pin(unsigned int id, const char *repository, unsigned int mode)
Definition: pin.c:228
void hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action, const char *message,...)
Definition: libhsm.c:207
#define SEM_KEY
Definition: pin.c:52
int hsm_logout_pin()
Definition: pin.c:413
#define SHM_KEY
Definition: pin.c:51
char * hsm_check_pin(unsigned int id, const char *repository, unsigned int mode)
Definition: pin.c:325
#define SEM_PERM
Definition: pin.c:54
#define SHM_PERM
Definition: pin.c:53
Definition: pin.c:58
int val
Definition: pin.c:59
struct semid_ds * buf
Definition: pin.c:60
unsigned short * array
Definition: pin.c:61