1 | /** |
---|
2 | ** abac_util.c |
---|
3 | **/ |
---|
4 | #include <err.h> |
---|
5 | #include <stdlib.h> |
---|
6 | #include <string.h> |
---|
7 | #include <stdio.h> |
---|
8 | #include <assert.h> |
---|
9 | #include <stdarg.h> |
---|
10 | #include <sys/stat.h> |
---|
11 | #include <termios.h> |
---|
12 | #include <unistd.h> |
---|
13 | #include <sys/types.h> |
---|
14 | |
---|
15 | #include <credentials/certificates/certificate.h> |
---|
16 | #include <credentials/certificates/x509.h> |
---|
17 | #include <credentials/keys/private_key.h> |
---|
18 | |
---|
19 | #include "abac_util.h" |
---|
20 | |
---|
21 | static int debug=0; |
---|
22 | |
---|
23 | /* Callback configuration */ |
---|
24 | struct cb_opts { |
---|
25 | int use_prompt; /* Print a prompt to stderr */ |
---|
26 | int use_echo; /* If true, turn off input echo on stdin */ |
---|
27 | unsigned int tries; /* Number of attempts allowed */ |
---|
28 | char prompt[20]; /* The prompt to display if use_echo is true */ |
---|
29 | }; |
---|
30 | |
---|
31 | /** potato pw length */ |
---|
32 | #define PWLEN 128 |
---|
33 | |
---|
34 | /** SHA string length */ |
---|
35 | #define SHA1_LENGTH 40 |
---|
36 | |
---|
37 | /****************************************************************/ |
---|
38 | char *abac_version() |
---|
39 | { |
---|
40 | DEBUG_PRINTF("abac_version is %s\n", ABAC_VERSION); |
---|
41 | return ABAC_VERSION; |
---|
42 | } |
---|
43 | |
---|
44 | char *prologIt(char *str) |
---|
45 | { |
---|
46 | char *tmp=NULL; |
---|
47 | asprintf(&tmp,"p%s",str); |
---|
48 | return tmp; |
---|
49 | } |
---|
50 | |
---|
51 | void abac_clean_string(char *string) |
---|
52 | { |
---|
53 | int len=strlen(string); |
---|
54 | int i; |
---|
55 | for(i=0;i<len;i++) |
---|
56 | string[i]=0; |
---|
57 | } |
---|
58 | |
---|
59 | void abac_errx(int eval, const char *msg) |
---|
60 | { |
---|
61 | errx(eval,"%s",msg); |
---|
62 | } |
---|
63 | |
---|
64 | /** |
---|
65 | * Malloc, fatal on error. |
---|
66 | */ |
---|
67 | void *abac_xmalloc(size_t size) { |
---|
68 | void *ret; |
---|
69 | |
---|
70 | ret = malloc(size); |
---|
71 | if (ret == NULL) |
---|
72 | err(1, "malloc"); |
---|
73 | |
---|
74 | return ret; |
---|
75 | } |
---|
76 | |
---|
77 | void *abac_xrealloc(void *ptr, size_t size) { |
---|
78 | void *ret = realloc(ptr, size); |
---|
79 | if (ret == NULL) |
---|
80 | err(1, "couldn't realloc %d bytes\n", size); |
---|
81 | return ret; |
---|
82 | } |
---|
83 | |
---|
84 | |
---|
85 | /** |
---|
86 | * strdup fatal on error |
---|
87 | */ |
---|
88 | char *abac_xstrdup(char *source) { |
---|
89 | char *ret; |
---|
90 | |
---|
91 | if (source == NULL) { |
---|
92 | return NULL; |
---|
93 | } |
---|
94 | |
---|
95 | ret = strdup(source); |
---|
96 | if (ret == NULL) |
---|
97 | err(1, "strdup"); |
---|
98 | |
---|
99 | return ret; |
---|
100 | } |
---|
101 | |
---|
102 | /* make a brand new string with or without being trimmed */ |
---|
103 | char *abac_trim_quotes(char *string) { |
---|
104 | char *tmp=abac_xstrdup(string); |
---|
105 | int len=strlen(tmp); |
---|
106 | if( (tmp[len-1] == '\'' || tmp[len-1] == '"') && |
---|
107 | (tmp[0] == '\'' || tmp[0] == '"')) { |
---|
108 | tmp[len-1]='\0'; |
---|
109 | char *ntmp=abac_xstrdup(&tmp[1]); |
---|
110 | free(tmp); |
---|
111 | return ntmp; |
---|
112 | } |
---|
113 | return tmp; |
---|
114 | } |
---|
115 | |
---|
116 | /** |
---|
117 | * Split a string based on the given delimiter. |
---|
118 | */ |
---|
119 | void abac_split(char *string, char *delim, char **ret, int *num) { |
---|
120 | int len = strlen(delim); |
---|
121 | char *start = string; |
---|
122 | int count = 0; |
---|
123 | |
---|
124 | // split the string by the delim |
---|
125 | while ((start = strstr(string, delim)) != NULL) { |
---|
126 | *start = 0; |
---|
127 | ret[count++] = string; |
---|
128 | string = start + len; |
---|
129 | } |
---|
130 | ret[count++] = string; |
---|
131 | |
---|
132 | *num = count; |
---|
133 | } |
---|
134 | |
---|
135 | int abac_validate_clean_name(char *string) { |
---|
136 | int i; |
---|
137 | |
---|
138 | assert(string != NULL); |
---|
139 | |
---|
140 | // must start with a letter/number |
---|
141 | if (!isalnum(string[0])) return 0; |
---|
142 | |
---|
143 | // Name must be alphanumeric or - |
---|
144 | for (i = 1; string[i] != '\0'; ++i) |
---|
145 | if (!isalnum(string[i]) && string[i] != '-') |
---|
146 | return 0; |
---|
147 | |
---|
148 | return 1; |
---|
149 | } |
---|
150 | |
---|
151 | /* check up to first ( if its there.. |
---|
152 | a.role(this) |
---|
153 | a.role(?,?Year:[100..200],?Value:[one,two,three]) |
---|
154 | a.role(isi) |
---|
155 | */ |
---|
156 | int abac_validate_clean_aspect_name(char *string) { |
---|
157 | int i; |
---|
158 | |
---|
159 | assert(string != NULL); |
---|
160 | |
---|
161 | // must start with a letter/number |
---|
162 | if (!isalnum(string[0])) return 0; |
---|
163 | |
---|
164 | // Name must be alphanumeric or - or _ up to the ( if there is one |
---|
165 | for (i = 1; string[i] != '\0' && string[i] != '(' ; ++i) |
---|
166 | if (!isalnum(string[i]) && string[i] != '-' && |
---|
167 | string[i] != '_' ) |
---|
168 | return 0; |
---|
169 | return 1; |
---|
170 | } |
---|
171 | |
---|
172 | chunk_t abac_generate_serial() { |
---|
173 | chunk_t serial = chunk_empty; |
---|
174 | |
---|
175 | // create a serial (stolen from strongswan pki) |
---|
176 | rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); |
---|
177 | if (!rng) |
---|
178 | errx(1, "no random number generator"); |
---|
179 | |
---|
180 | rng->allocate_bytes(rng, 8, &serial); |
---|
181 | while (serial.ptr[0] == 0) { |
---|
182 | // don't get leading 0's |
---|
183 | rng->get_bytes(rng, 1, serial.ptr); |
---|
184 | } |
---|
185 | rng->destroy(rng); |
---|
186 | |
---|
187 | DEBUG_PRINTF("abac_generate_serial, serial generated is %#B\n", &serial); |
---|
188 | return serial; |
---|
189 | } |
---|
190 | |
---|
191 | // validate a princpal's name |
---|
192 | // makes sure it's a valid SHA1 identifier |
---|
193 | // return values: |
---|
194 | // success: malloc'd copy with all hex digits lowercase |
---|
195 | // fail: NULL |
---|
196 | char *abac_validate_principal(char *keyid) { |
---|
197 | int i; |
---|
198 | char *copy = NULL; |
---|
199 | |
---|
200 | if (strlen(keyid) != SHA1_LENGTH) |
---|
201 | return NULL; |
---|
202 | |
---|
203 | int len = strlen(keyid) + 1; |
---|
204 | copy = abac_xmalloc(len); |
---|
205 | sprintf(copy, "%s", keyid); |
---|
206 | |
---|
207 | i=0; |
---|
208 | for (; i < SHA1_LENGTH; ++i) { |
---|
209 | copy[i] = tolower(copy[i]); |
---|
210 | if (!isxdigit(copy[i])) |
---|
211 | goto error; |
---|
212 | } |
---|
213 | return copy; |
---|
214 | error: |
---|
215 | free(copy); |
---|
216 | return NULL; |
---|
217 | } |
---|
218 | |
---|
219 | // parse&validate the validity |
---|
220 | int abac_validate_validity_string(char *validity_str) |
---|
221 | { |
---|
222 | int validity=0; |
---|
223 | if (validity_str != NULL) { |
---|
224 | char suffix = 'd'; // default suffix is days |
---|
225 | int multiplier; |
---|
226 | |
---|
227 | int len = strlen(validity_str); |
---|
228 | assert(len > 0); |
---|
229 | |
---|
230 | // get the suffix char if it's alphabetical |
---|
231 | if (isalpha(validity_str[len - 1])) { |
---|
232 | suffix = validity_str[len - 1]; |
---|
233 | |
---|
234 | // truncate |
---|
235 | validity_str[len - 1] = '\0'; |
---|
236 | --len; |
---|
237 | |
---|
238 | // make sure it's not only a suffix |
---|
239 | if (len == 0) { |
---|
240 | errx(1,"Invalid validity\n"); |
---|
241 | } |
---|
242 | } |
---|
243 | |
---|
244 | // convert the suffix to a multiplier |
---|
245 | switch(suffix) { |
---|
246 | case 's': multiplier = 1; break; |
---|
247 | case 'm': multiplier = 60; break; |
---|
248 | case 'h': multiplier = 3600; break; |
---|
249 | case 'd': multiplier = 86400; break; |
---|
250 | case 'y': multiplier = 31536000; break; |
---|
251 | default: |
---|
252 | errx(1,"Invalid suffix, must be s m h d y\n"); |
---|
253 | } |
---|
254 | |
---|
255 | // ascii to int |
---|
256 | char *end; |
---|
257 | validity = strtol(validity_str, &end, 10); |
---|
258 | if (end - validity_str < len) { |
---|
259 | errx(1,"Invalid validity\n"); |
---|
260 | } |
---|
261 | |
---|
262 | if (validity <= 0) { |
---|
263 | errx(1,"Invalid validity: must be > 0\n"); |
---|
264 | } |
---|
265 | |
---|
266 | // multiply! |
---|
267 | validity *= multiplier; |
---|
268 | } |
---|
269 | return validity; |
---|
270 | } |
---|
271 | |
---|
272 | |
---|
273 | int file_exist(char *filename) |
---|
274 | { |
---|
275 | struct stat stbuf; |
---|
276 | if(stat(filename,&stbuf) == -1) |
---|
277 | return 0; |
---|
278 | return 1; |
---|
279 | } |
---|
280 | |
---|
281 | |
---|
282 | chunk_t abac_get_potato_file(char *filename) |
---|
283 | { |
---|
284 | chunk_t pp=chunk_empty; |
---|
285 | if(file_exist(filename)) { |
---|
286 | DEBUG_PRINTF("trying to open %s\n", filename); |
---|
287 | FILE *fp=fopen(filename,"r"); |
---|
288 | char str[PWLEN]; |
---|
289 | int rc=fscanf(fp,"%s",str); |
---|
290 | if(rc) { |
---|
291 | pp.ptr=abac_xstrdup(str); |
---|
292 | pp.len=strlen(pp.ptr); |
---|
293 | if(str[pp.len-1]=='\n') |
---|
294 | pp.len--; |
---|
295 | } |
---|
296 | abac_clean_string(str); |
---|
297 | fclose(fp); |
---|
298 | } |
---|
299 | return pp; |
---|
300 | } |
---|
301 | |
---|
302 | /*** |
---|
303 | ***/ |
---|
304 | chunk_t abac_get_potato_cb(int try, char *name) { |
---|
305 | /* Get a password from stdin and return it as a chunk_t. If too many tries |
---|
306 | * have occurred or there is any other problem, return an empty chunk_t, |
---|
307 | * which libstrongswan takes as giving up. The chunk is alloated here |
---|
308 | * (inside getline), and presumably freed by libstrongswan. User points to |
---|
309 | * a cb_opts struct, which affects this routine in the obvious ways. |
---|
310 | */ |
---|
311 | /* Configuration options */ |
---|
312 | |
---|
313 | if(name!=NULL) { |
---|
314 | char *n=(char *)memrchr(name,'/',strlen(name)); |
---|
315 | if(n==NULL) |
---|
316 | printf("[%s] ", name); |
---|
317 | else printf("[%s] ",n); |
---|
318 | } |
---|
319 | struct cb_opts c_opts = { 1, 0, 3, "Key passphrase:" }; |
---|
320 | struct cb_opts *opts = &c_opts; |
---|
321 | chunk_t rv = chunk_empty; /* Return value, starts empty */ |
---|
322 | |
---|
323 | if (try -1 < opts->tries ) { |
---|
324 | struct termios t; /* Terminal settings */ |
---|
325 | size_t len = 0; /* Length of string from getline */ |
---|
326 | tcflag_t orig = 0; /* Holds the original local flags (echo in here) */ |
---|
327 | |
---|
328 | if (!opts->use_echo) { |
---|
329 | /* Use tc{get,set}attr to turn echo off and restore the intial |
---|
330 | * echo settings */ |
---|
331 | if (!tcgetattr(0, &t)) { |
---|
332 | orig = t.c_lflag; |
---|
333 | |
---|
334 | t.c_lflag &= ~ECHO; |
---|
335 | if ( tcsetattr(0, TCSANOW, &t) ) { |
---|
336 | perror("Cannot turn off echo"); |
---|
337 | return rv; |
---|
338 | } |
---|
339 | } |
---|
340 | else { |
---|
341 | perror("Cannot turn get attributes to off echo"); |
---|
342 | return rv; |
---|
343 | } |
---|
344 | } |
---|
345 | if (opts->use_prompt) printf("%s", opts->prompt); |
---|
346 | |
---|
347 | /* Because rv.ptr starts as NULL, getline allocates memory. The size |
---|
348 | * of the allocation returns in rv.len and the size of the string |
---|
349 | * (including newline and NUL) is in len. */ |
---|
350 | if ((rv.ptr = (u_char *) malloc(rv.len = PWLEN))) { |
---|
351 | if ( fgets(rv.ptr, rv.len, stdin) ) { |
---|
352 | /* Readjust the chunk_t's len field to the size of the string |
---|
353 | * w/o the newline or NUL */ |
---|
354 | /* would prefer strnlen, but no such luck in FBSD7 or earlier*/ |
---|
355 | size_t len = strlen(rv.ptr); |
---|
356 | |
---|
357 | /* \n\0, \n or \0 */ |
---|
358 | if (rv.ptr[len-2] == '\n') rv.len = len-2; |
---|
359 | else if (rv.ptr[len-1] == '\n') rv.len = len-1; |
---|
360 | else rv.len = len -1; |
---|
361 | } else { |
---|
362 | /* Read failed. Deallocate and clear rv */ |
---|
363 | free(rv.ptr); |
---|
364 | rv = chunk_empty; |
---|
365 | } |
---|
366 | } |
---|
367 | else { |
---|
368 | /* Failed malloc. Restore rv to empty and return it */ |
---|
369 | perror("malloc"); |
---|
370 | rv = chunk_empty; |
---|
371 | return rv; |
---|
372 | } |
---|
373 | |
---|
374 | if (!opts->use_echo ) { |
---|
375 | /* Pop echo beck to its original setting. */ |
---|
376 | t.c_lflag = orig; |
---|
377 | |
---|
378 | if ( tcsetattr(0, TCSANOW, &t) ) |
---|
379 | perror("Cannot restore echo setting?"); |
---|
380 | |
---|
381 | if (opts->use_prompt) printf("\n"); |
---|
382 | } |
---|
383 | } |
---|
384 | else fprintf(stderr, "Too many tries (%d)", try-1); |
---|
385 | return rv; |
---|
386 | } |
---|
387 | |
---|
388 | chunk_t extract_potato(char *filename, char *pfile) |
---|
389 | { |
---|
390 | chunk_t pp; |
---|
391 | if(pfile==NULL || strlen(pfile)==0 ) { |
---|
392 | pp=abac_get_potato_cb(2,filename); |
---|
393 | } else { |
---|
394 | pp=abac_get_potato_file(pfile); |
---|
395 | } |
---|
396 | return pp; |
---|
397 | } |
---|