1 |
/* |
2 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
3 |
* you may not use this file except in compliance with the License. |
4 |
* You may obtain a copy of the License at |
5 |
* |
6 |
* http://www.apache.org/licenses/LICENSE-2.0 |
7 |
* |
8 |
* Unless required by applicable law or agreed to in writing, software |
9 |
* distributed under the License is distributed on an "AS IS" BASIS, |
10 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
11 |
* See the License for the specific language governing permissions and |
12 |
* limitations under the License. |
13 |
* |
14 |
* Authors: Mischa Sall\'e, Dennis van Dok, Oscar Koeroo |
15 |
* NIKHEF Amsterdam, the Netherlands |
16 |
* <grid-mw-security@nikhef.nl> |
17 |
*/ |
18 |
|
19 |
/* |
20 |
* Command line interface program to interact with LCAS and LCMAPS, e.g. to |
21 |
* follow from userspace the steps gLExec takes. Compile with e.g. |
22 |
* gcc -ldl -rdynamic -o llrun llrun.c |
23 |
* or |
24 |
* gcc -ldl -L. -lvomsfix -o llrun llrun.c |
25 |
* to solve a missing symbol problem with libvomsapi / liblcmaps. The first |
26 |
* version uses the functions defined inside this file, the second gets them |
27 |
* from the dummy library libvomsfix.so |
28 |
*/ |
29 |
|
30 |
#include <stdio.h> |
31 |
#include <stdarg.h> |
32 |
#include <stdlib.h> |
33 |
|
34 |
#include <string.h> |
35 |
#include <errno.h> |
36 |
|
37 |
#include <sys/types.h> |
38 |
#include <sys/stat.h> |
39 |
#include <fcntl.h> |
40 |
#include <unistd.h> |
41 |
|
42 |
#include <pwd.h> |
43 |
#include <grp.h> |
44 |
|
45 |
#include <dlfcn.h> |
46 |
|
47 |
#include <syslog.h> |
48 |
|
49 |
#define VERSION "0.1.0-1" |
50 |
|
51 |
/* Define to have getopt() behave POSIX correctly */ |
52 |
#define POSIXLY_CORRECT |
53 |
|
54 |
/* Dirty hack to fix the missing functions from VOMS API: VOMS API should have |
55 |
* defined these extern "C". LCMAPS needs these functions, and if not using the |
56 |
* ones from LCAS, you can use these (trivial ones) instead. By compiling with |
57 |
* -rdynamic i.e. by linking with -export-dynamic, the following symbols are |
58 |
* used instead. */ |
59 |
int getMajorVersionNumber(void) { return 0; } |
60 |
int getPatchVersionNumber(void) { return 0; } |
61 |
int getMinorVersionNumber(void) { return 0; } |
62 |
|
63 |
/************************************************************************/ |
64 |
/* TYPEDEFS */ |
65 |
/************************************************************************/ |
66 |
|
67 |
/* Global options */ |
68 |
typedef struct { |
69 |
int verbose; /* Whether to print extra warnings */ |
70 |
int do_lcas; /* Whether to do LCAS */ |
71 |
int do_lcmaps; /* Whether to run LCMAPS */ |
72 |
char *syslog_fac; /* which syslog facility to use */ |
73 |
} opts_t; |
74 |
|
75 |
/* Credentials */ |
76 |
typedef struct { |
77 |
char *pemstring; /* Will contain a full pemstring */ |
78 |
char *dn; /* Will contain a DN */ |
79 |
int nfqan; /* Number of specified FQANs */ |
80 |
char **fqans; /* Specified FQANs */ |
81 |
} cred_t; |
82 |
|
83 |
/* lcas_request_t is defined in lcas_types.h, can just re-typedef it here. */ |
84 |
#if 0 |
85 |
/*#include "lcas_types.h"*/ |
86 |
#else |
87 |
typedef char *lcas_request_t; |
88 |
#endif |
89 |
|
90 |
/* lcmaps_account_info_t is defined in lcmaps_account.h, |
91 |
* can just re-typedef it here. */ |
92 |
#if 0 |
93 |
#include "lcmaps_account.h" |
94 |
#else |
95 |
typedef struct lcmaps_account_info_s |
96 |
{ |
97 |
uid_t uid; /* the uid of the local account */ |
98 |
gid_t * pgid_list; /* the list of primary gids */ |
99 |
int npgid; /* the number of primary gids found */ |
100 |
gid_t * sgid_list; /* the list of secondary gids */ |
101 |
int nsgid; /* the number of secondary gids found */ |
102 |
char * poolindex; /* the pool index */ |
103 |
} lcmaps_account_info_t; |
104 |
#endif |
105 |
|
106 |
/* LCMAPS mode type: determines the LCMAPS interface to be used */ |
107 |
typedef enum { |
108 |
LCMAPS_RETURN_ACCOUNT_FROM_PEM, |
109 |
LCMAPS_RETURN_ACCOUNT_WITHOUT_GSI, |
110 |
LCMAPS_RETURN_POOLINDEX_WITHOUT_GSI, |
111 |
} lcmaps_mode_t; |
112 |
|
113 |
|
114 |
/* Struct containing all the lcmaps related variables, handles and functions, |
115 |
* will be filled using dlsym() */ |
116 |
/* List extended with Without-GSI specific functions */ |
117 |
typedef struct { |
118 |
/* Variables */ |
119 |
int new; /* new API */ |
120 |
int dovoms; /* whether to run voms */ |
121 |
lcmaps_mode_t mode; /* type of LCMAPS mode */ |
122 |
FILE *logfile; /* logfile or NULL for stdout */ |
123 |
opts_t *opts; /* global credentials */ |
124 |
cred_t *cred; /* global credentials */ |
125 |
lcmaps_account_info_t account; /* resulting account info */ |
126 |
/* Library handles */ |
127 |
void *handle,*helper; /* Needed for dlclose() */ |
128 |
/* Functions */ |
129 |
int (*lcmaps_init)(FILE*); |
130 |
int (*lcmaps_account_info_init)(lcmaps_account_info_t*); |
131 |
int (*lcmaps_return_account_from_pem)(char*,int,lcmaps_account_info_t*); |
132 |
int (*lcmaps_return_poolindex_without_gsi)(char*,char**,int, |
133 |
lcmaps_account_info_t*); |
134 |
/* int (*lcmaps_return_poolindex_with_mapcounter)(char*,char**,int,int, |
135 |
lcmaps_account_info_t); */ |
136 |
int (*lcmaps_return_account_without_gsi)(char*,char**,int,int, |
137 |
lcmaps_account_info_t*); |
138 |
int (*lcmaps_term)(void); |
139 |
int (*lcmaps_account_info_clean)(lcmaps_account_info_t*); |
140 |
int (*lcmaps_get_major_version)(void); |
141 |
int (*lcmaps_get_minor_version)(void); |
142 |
int (*lcmaps_get_patch_version)(void); |
143 |
void (*lcmaps_disable_voms_attributes_verification)(void); |
144 |
void (*lcmaps_enable_voms_attributes_verification)(void); |
145 |
int (*lcmaps_is_set_to_verify_voms_attributes)(void); |
146 |
} lcmaps_t; |
147 |
|
148 |
|
149 |
/* Struct containing all the lcas functions, will be filled using dlsym() */ |
150 |
typedef struct { |
151 |
/* Variables */ |
152 |
char *rsl; |
153 |
FILE *logfile; /* logfile or NULL for stdout */ |
154 |
opts_t *opts; /* global credentials */ |
155 |
cred_t *cred; /* global credentials */ |
156 |
/* Library handles */ |
157 |
void *handle; /* Needed for dlclose() */ |
158 |
/* Functions */ |
159 |
int (*lcas_init)(FILE*); |
160 |
int (*lcas_pem)(char*,lcas_request_t); |
161 |
int (*lcas_term)(void); |
162 |
} lcas_t; |
163 |
|
164 |
|
165 |
/************************************************************************/ |
166 |
/* GLOBAL VARIABLE */ |
167 |
/************************************************************************/ |
168 |
|
169 |
/* Short program name, set in main() */ |
170 |
static const char *prog=NULL; |
171 |
|
172 |
|
173 |
/************************************************************************/ |
174 |
/* FUNCTIONS */ |
175 |
/************************************************************************/ |
176 |
|
177 |
/* Prints a notice on stdout */ |
178 |
void llnotice(char *format, ...) { |
179 |
va_list args; |
180 |
|
181 |
fprintf(stdout,"[%s]: ", prog); |
182 |
va_start(args,format); |
183 |
vfprintf(stdout,format,args); |
184 |
} |
185 |
|
186 |
/* Prints a warning on stderr */ |
187 |
void llwarn(char *format, ...) { |
188 |
va_list args; |
189 |
|
190 |
fprintf(stderr,"[%s]: WARNING: ", prog); |
191 |
va_start(args,format); |
192 |
vfprintf(stderr,format,args); |
193 |
} |
194 |
|
195 |
/* Prints an error on stderr */ |
196 |
void llerr(char *format, ...) { |
197 |
va_list args; |
198 |
|
199 |
fprintf(stderr,"[%s]: ERROR: ", prog); |
200 |
va_start(args,format); |
201 |
vfprintf(stderr,format,args); |
202 |
} |
203 |
|
204 |
/* Opens the correct syslog facility. Note that the actual opening does not |
205 |
* happen until the first message is logged, see openlog(3) |
206 |
* Return syslog_fac or -1 on error */ |
207 |
int opensyslog(const char *name) { |
208 |
int syslog_fac=-1; |
209 |
|
210 |
/* Now go over all the possibilities */ |
211 |
if (strcmp(name,"LOG_KERN")==0) |
212 |
syslog_fac=LOG_KERN; |
213 |
else if (strcmp(name,"LOG_USER")==0) |
214 |
syslog_fac=LOG_USER; |
215 |
else if (strcmp(name,"LOG_MAIL")==0) |
216 |
syslog_fac=LOG_MAIL; |
217 |
else if (strcmp(name,"LOG_NEWS")==0) |
218 |
syslog_fac=LOG_NEWS; |
219 |
else if (strcmp(name,"LOG_UUCP")==0) |
220 |
syslog_fac=LOG_UUCP; |
221 |
else if (strcmp(name,"LOG_DAEMON")==0) |
222 |
syslog_fac=LOG_DAEMON; |
223 |
else if (strcmp(name,"LOG_AUTH")==0) |
224 |
syslog_fac=LOG_AUTH; |
225 |
else if (strcmp(name,"LOG_CRON")==0) |
226 |
syslog_fac=LOG_CRON; |
227 |
else if (strcmp(name,"LOG_LPR")==0) |
228 |
syslog_fac=LOG_LPR; |
229 |
else if (strcmp(name,"LOG_LOCAL0")==0) |
230 |
syslog_fac=LOG_LOCAL0; |
231 |
else if (strcmp(name,"LOG_LOCAL1")==0) |
232 |
syslog_fac=LOG_LOCAL1; |
233 |
else if (strcmp(name,"LOG_LOCAL2")==0) |
234 |
syslog_fac=LOG_LOCAL2; |
235 |
else if (strcmp(name,"LOG_LOCAL3")==0) |
236 |
syslog_fac=LOG_LOCAL3; |
237 |
else if (strcmp(name,"LOG_LOCAL4")==0) |
238 |
syslog_fac=LOG_LOCAL4; |
239 |
else if (strcmp(name,"LOG_LOCAL5")==0) |
240 |
syslog_fac=LOG_LOCAL5; |
241 |
else if (strcmp(name,"LOG_LOCAL6")==0) |
242 |
syslog_fac=LOG_LOCAL6; |
243 |
else if (strcmp(name,"LOG_LOCAL7")==0) |
244 |
syslog_fac=LOG_LOCAL7; |
245 |
/* Now the non-standard ones... */ |
246 |
#ifdef LOG_SYSLOG |
247 |
else if (strcmp(name,"LOG_SYSLOG")==0) |
248 |
syslog_fac=LOG_SYSLOG; |
249 |
#endif |
250 |
#ifdef LOG_FTP |
251 |
else if (strcmp(name,"LOG_FTP")==0) |
252 |
syslog_fac=LOG_FTP; |
253 |
#endif |
254 |
#ifdef LOG_AUTHPRIV |
255 |
else if (strcmp(name,"LOG_AUTHPRIV")==0) |
256 |
syslog_fac=LOG_AUTHPRIV; |
257 |
#endif |
258 |
#ifdef LOG_AUDIT |
259 |
else if (strcmp(name,"LOG_AUDIT")==0) |
260 |
syslog_fac=LOG_AUDIT; |
261 |
#endif |
262 |
|
263 |
/* Is it valid? */ |
264 |
if (syslog_fac==-1) |
265 |
llerr("Unknown syslog facility '%s' specified.\n",name); |
266 |
else |
267 |
openlog(prog,(LOG_CONS|LOG_PID),syslog_fac); |
268 |
|
269 |
return syslog_fac; |
270 |
} |
271 |
|
272 |
/* Reads in user proxy (on which mapping is based) from filename or NULL on |
273 |
* error */ |
274 |
char *readproxy(const char *filename) { |
275 |
int fd,size; |
276 |
char *pemstring; |
277 |
struct stat st; |
278 |
|
279 |
/* Open file and get size */ |
280 |
if ((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&st)==-1) { |
281 |
llerr("Cannot open or stat file %s: %s\n", filename, strerror(errno)); |
282 |
return NULL; |
283 |
} |
284 |
|
285 |
/* Reserve memory */ |
286 |
if ((pemstring=(char *)malloc((size_t)(st.st_size+sizeof(char))))==NULL) { |
287 |
llerr("Cannot malloc %d bytes for pemstring\n", (int)st.st_size); |
288 |
return NULL; |
289 |
} |
290 |
|
291 |
/* Read file */ |
292 |
size=read(fd,pemstring,(size_t)st.st_size); |
293 |
if (size!=st.st_size) { |
294 |
llerr("Number of bytes read %d != size %d\n", size,(int)st.st_size); |
295 |
return NULL; |
296 |
} |
297 |
|
298 |
/* Close file */ |
299 |
close(fd); |
300 |
/* Add '\0' and return */ |
301 |
pemstring[size]='\0'; |
302 |
|
303 |
return pemstring; |
304 |
} |
305 |
|
306 |
/************************************************************************/ |
307 |
/* LCMAPS FUNCTIONS */ |
308 |
/************************************************************************/ |
309 |
|
310 |
/* Parses the options for LCMAPS and opens the logfile when needed */ |
311 |
int lcmaps_set_vars(char *options, lcmaps_t *lcmaps) { |
312 |
char *var=options,*value,*end,*pos; |
313 |
|
314 |
/* Set defaults */ |
315 |
lcmaps->new=0; /* assume old when unspecified */ |
316 |
lcmaps->dovoms=-1; /* unspecified */ |
317 |
lcmaps->mode=LCMAPS_RETURN_ACCOUNT_FROM_PEM; |
318 |
|
319 |
/* If first char of options is a - it's actually the next main option */ |
320 |
if (options==NULL || options[0]=='-') |
321 |
return 0; |
322 |
|
323 |
do { |
324 |
/* Find end of current var=value pair */ |
325 |
end=strchr(var, ','); |
326 |
if (end!=NULL) end[0]='\0'; |
327 |
/* Find end of variable name */ |
328 |
pos=strchr(var,'='); |
329 |
if (pos==NULL) |
330 |
llwarn("Unrecognized element '%s'\n",var); |
331 |
else { |
332 |
pos[0]='\0'; |
333 |
value=pos+1; |
334 |
/* Find the variable */ |
335 |
if (strcmp(var,"debug")==0) |
336 |
setenv("LCMAPS_DEBUG_LEVEL",value,1); |
337 |
else if (strcmp(var,"policy")==0) |
338 |
setenv("LCMAPS_POLICY_NAME",value,1); |
339 |
else if (strcmp(var,"db")==0) |
340 |
setenv("LCMAPS_DB_FILE",value,1); |
341 |
else if (strcmp(var,"file")==0) { |
342 |
/* Only open when not already linked to stderr */ |
343 |
if (lcmaps->logfile==NULL) { |
344 |
if ( (lcmaps->logfile=fopen(value,"a"))==NULL) |
345 |
llwarn("Cannot open %s: %s\n", value,strerror(errno)); |
346 |
} |
347 |
} else if (strcmp(var,"mode")==0) { |
348 |
if (strcmp(value, "pem") == 0) { |
349 |
lcmaps->mode = LCMAPS_RETURN_ACCOUNT_FROM_PEM; |
350 |
} else if (strcmp(value, "nogsi_pi") == 0) { |
351 |
lcmaps->mode = LCMAPS_RETURN_POOLINDEX_WITHOUT_GSI; |
352 |
} else if (strcmp(value, "nogsi_ga") == 0) { |
353 |
lcmaps->mode = LCMAPS_RETURN_ACCOUNT_WITHOUT_GSI; |
354 |
} else { |
355 |
llerr("LCMAPS mode should be pem, nogsi_pi or nogsi_ga.\n"); |
356 |
return 1; |
357 |
} |
358 |
} else if (strcmp(var,"voms")==0) { |
359 |
if (strcmp(value, "0")==0) { |
360 |
lcmaps->dovoms=0; |
361 |
} else if (strcmp(value, "1") == 0) { |
362 |
lcmaps->dovoms=1; |
363 |
} else { |
364 |
llerr("Invalid value %s for option voms.\n", value); |
365 |
return 1; |
366 |
} |
367 |
} else |
368 |
llwarn("Unrecognized option '%s'\n",var); |
369 |
/* reset value at pos */ |
370 |
pos[0]='='; |
371 |
} |
372 |
if (end!=NULL) { |
373 |
/* reset value at end */ |
374 |
end[0]=','; |
375 |
/* advance to next option */ |
376 |
var=end+1; |
377 |
} |
378 |
} while (end!=NULL); |
379 |
return 0; |
380 |
} |
381 |
|
382 |
/* Prints contents of account */ |
383 |
void lcmaps_print_account(lcmaps_account_info_t* account) { |
384 |
int i; |
385 |
struct passwd *pw; |
386 |
struct group *gr; |
387 |
|
388 |
/* Check if there is anything */ |
389 |
if (account->uid==-1) { |
390 |
llnotice("Account info is empty.\n"); |
391 |
return; |
392 |
} |
393 |
/* UID / username */ |
394 |
pw=getpwuid(account->uid); |
395 |
llnotice("uid=%d(%s)\n",account->uid,pw ? pw->pw_name : "undefined"); |
396 |
/* Primary groups */ |
397 |
llnotice("primary gids: %d\n",account->npgid); |
398 |
for (i=0; i<account->npgid; i++) { |
399 |
gr=getgrgid(account->pgid_list[i]); |
400 |
llnotice("pgid[%d]=%d(%s)\n",i, |
401 |
account->pgid_list[i], |
402 |
gr ? gr->gr_name : "undefined"); |
403 |
} |
404 |
/* Secondary groups */ |
405 |
llnotice("secondary gids: %d\n",account->nsgid); |
406 |
for (i=0; i<account->nsgid; i++) { |
407 |
gr=getgrgid(account->sgid_list[i]); |
408 |
llnotice("sgid[%d]=%d(%s)\n",i, |
409 |
account->sgid_list[i], |
410 |
gr ? gr->gr_name : "undefined"); |
411 |
} |
412 |
/* Poolindex */ |
413 |
llnotice("poolindex=%s\n", |
414 |
(account->poolindex)!=NULL ? account->poolindex : "undefined"); |
415 |
} |
416 |
|
417 |
/* Dynamically loads LCMAPS library */ |
418 |
int lcmaps_loadlib(lcmaps_t *lcmaps,opts_t *opts) { |
419 |
const char *libname; |
420 |
|
421 |
switch (lcmaps->mode) { |
422 |
case LCMAPS_RETURN_ACCOUNT_FROM_PEM: |
423 |
libname="liblcmaps_return_account_from_pem.so"; |
424 |
break; |
425 |
case LCMAPS_RETURN_POOLINDEX_WITHOUT_GSI: |
426 |
libname="liblcmaps_return_poolindex_without_gsi.so"; |
427 |
break; |
428 |
case LCMAPS_RETURN_ACCOUNT_WITHOUT_GSI: |
429 |
libname="liblcmaps_return_poolindex_without_gsi.so"; |
430 |
break; |
431 |
default: |
432 |
llerr("Unknown LCMAPS mode.\n"); |
433 |
return 1; |
434 |
} |
435 |
|
436 |
/* Make sure lib->handle has welldefined value */ |
437 |
lcmaps->handle=lcmaps->helper=NULL; |
438 |
|
439 |
/* Load the library lazily: this allows checking for missing symbols */ |
440 |
if ( (lcmaps->handle=dlopen(libname, RTLD_LAZY | RTLD_GLOBAL))==NULL ) { |
441 |
llerr("Cannot open LCMAPS lib: %s\n", dlerror()); |
442 |
return 1; |
443 |
} |
444 |
|
445 |
/* Clear dlerror() */ |
446 |
dlerror(); |
447 |
|
448 |
/* See if we have lcmaps_get*version() functions */ |
449 |
lcmaps->lcmaps_get_major_version= |
450 |
(int(*)(void))dlsym(lcmaps->handle,"lcmaps_get_major_version"); |
451 |
if (dlerror()==NULL) /* New LCMAPS: no need for get*VersionNumber() */ |
452 |
lcmaps->new=1; |
453 |
else { /* Old LCMAPS version */ |
454 |
lcmaps->new=0; |
455 |
if (opts->verbose) |
456 |
llwarn("Old LCMAPS version, "\ |
457 |
"need to provide missing get*VersionNumber() functions.\n"); |
458 |
|
459 |
/* Load global symbols, in order to look for getMajorVersionNumber */ |
460 |
if ((lcmaps->helper=dlopen(NULL,RTLD_NOW | RTLD_GLOBAL))==NULL) { |
461 |
llerr("Cannot load global symbols: %s\n",dlerror()); |
462 |
return 1; |
463 |
} |
464 |
|
465 |
/* Now look for getMajorVersionNumber: first look in global symbols, if |
466 |
* not there, try loading vomsfix library, if that fails too, load lcas |
467 |
* instead. */ |
468 |
dlsym(lcmaps->helper,"getMajorVersionNumber"); |
469 |
if (dlerror()!=NULL) { /* Not in global: try vomsfix lib */ |
470 |
dlclose(lcmaps->helper); /* No longer needed, doesn't provide...*/ |
471 |
if (opts->verbose) |
472 |
llwarn("trying libvomsfix.so for missing "\ |
473 |
"get*VersionNumber() functions.\n"); |
474 |
if ( (lcmaps->helper= |
475 |
dlopen("libvomsfix.so",RTLD_NOW | RTLD_GLOBAL))==NULL ) { |
476 |
/* libvomsfix.so doesn't exist or isn't found. Now use lcas as |
477 |
* a backup */ |
478 |
if (opts->verbose) |
479 |
llwarn("loading LCAS to provide missing "\ |
480 |
"get*VersionNumber() functions.\n"); |
481 |
if ( (lcmaps->helper= |
482 |
dlopen("liblcas.so",RTLD_NOW | RTLD_GLOBAL))==NULL) { |
483 |
llerr("%s\n",dlerror()); |
484 |
return 1; |
485 |
} |
486 |
} |
487 |
} |
488 |
} |
489 |
|
490 |
/* Reopening lcmaps with RTLD_NOW to force loading of secondary dependencies |
491 |
* (e.g. VOMSAPI) */ |
492 |
if (dlclose(lcmaps->handle)) { |
493 |
llerr("Cannot close LCMAPS lib: %s\n",dlerror()); |
494 |
return 1; |
495 |
} |
496 |
if ( (lcmaps->handle=dlopen(libname, RTLD_NOW | RTLD_GLOBAL))==NULL ) { |
497 |
llerr("%s\n",dlerror()); |
498 |
return 1; |
499 |
} |
500 |
|
501 |
return 0; |
502 |
} |
503 |
|
504 |
/* Dynamically loads LCMAPS library symbols */ |
505 |
int lcmaps_loadfcies(lcmaps_t *lcmaps) { |
506 |
char *err; |
507 |
|
508 |
/* Load functions */ |
509 |
lcmaps->lcmaps_init=(int (*)(FILE*)) |
510 |
dlsym(lcmaps->handle,"lcmaps_init"); |
511 |
if ( (err=dlerror())!=NULL) |
512 |
goto lcmapsfcies_failed; |
513 |
lcmaps->lcmaps_account_info_init=(int (*)(lcmaps_account_info_t*)) |
514 |
dlsym(lcmaps->handle,"lcmaps_account_info_init"); |
515 |
if ( (err=dlerror())!=NULL) |
516 |
goto lcmapsfcies_failed; |
517 |
lcmaps->lcmaps_term= (int (*)(void)) |
518 |
dlsym(lcmaps->handle,"lcmaps_term"); |
519 |
if ( (err=dlerror())!=NULL) |
520 |
goto lcmapsfcies_failed; |
521 |
lcmaps->lcmaps_account_info_clean=(int (*)(lcmaps_account_info_t*)) |
522 |
dlsym(lcmaps->handle,"lcmaps_account_info_clean"); |
523 |
if ( (err=dlerror())!=NULL) |
524 |
goto lcmapsfcies_failed; |
525 |
|
526 |
/* Load LCMAPS runmode specific function (account mapping function) */ |
527 |
switch (lcmaps->mode) { |
528 |
case LCMAPS_RETURN_ACCOUNT_FROM_PEM: |
529 |
lcmaps->lcmaps_return_account_from_pem= |
530 |
(int (*)(char*,int,lcmaps_account_info_t*)) |
531 |
dlsym(lcmaps->handle,"lcmaps_return_account_from_pem"); |
532 |
if ( (err=dlerror())!=NULL) |
533 |
goto lcmapsfcies_failed; |
534 |
break; |
535 |
case LCMAPS_RETURN_POOLINDEX_WITHOUT_GSI: |
536 |
lcmaps->lcmaps_return_poolindex_without_gsi= |
537 |
(int (*)(char*,char**,int,lcmaps_account_info_t*)) |
538 |
dlsym(lcmaps->handle,"lcmaps_return_poolindex_without_gsi"); |
539 |
if ( (err=dlerror())!=NULL) |
540 |
goto lcmapsfcies_failed; |
541 |
break; |
542 |
case LCMAPS_RETURN_ACCOUNT_WITHOUT_GSI: |
543 |
lcmaps->lcmaps_return_account_without_gsi= |
544 |
(int (*)(char*,char**,int,int,lcmaps_account_info_t*)) |
545 |
dlsym(lcmaps->handle,"lcmaps_return_account_without_gsi"); |
546 |
if ( (err=dlerror())!=NULL) |
547 |
goto lcmapsfcies_failed; |
548 |
break; |
549 |
} |
550 |
|
551 |
/* When we specified to either enable or disable VOMS, load both symbols */ |
552 |
if (lcmaps->dovoms!=-1) { |
553 |
lcmaps->lcmaps_enable_voms_attributes_verification= |
554 |
(void (*)(void)) |
555 |
dlsym(lcmaps->handle, |
556 |
"lcmaps_enable_voms_attributes_verification"); |
557 |
if ( (err=dlerror())!=NULL) { |
558 |
llerr("Requested API call for disabling voms is not present in " |
559 |
"this LCMAPS.\n"); |
560 |
goto lcmapsfcies_failed; |
561 |
} |
562 |
lcmaps->lcmaps_disable_voms_attributes_verification= |
563 |
(void (*)(void)) |
564 |
dlsym(lcmaps->handle, |
565 |
"lcmaps_disable_voms_attributes_verification"); |
566 |
if ( (err=dlerror())!=NULL) { |
567 |
llerr("Requested API call for disabling voms is not present in " |
568 |
"this LCMAPS.\n"); |
569 |
goto lcmapsfcies_failed; |
570 |
} |
571 |
} |
572 |
|
573 |
return 0; |
574 |
|
575 |
lcmapsfcies_failed: |
576 |
llerr("%s\n",err); |
577 |
dlclose(lcmaps->handle); |
578 |
if (lcmaps->helper) |
579 |
dlclose(lcmaps->helper); |
580 |
return 1; |
581 |
} |
582 |
|
583 |
/* Does an lcmaps run, for given credentials and to logfile or syslog when |
584 |
* logfile is NULL. */ |
585 |
int lcmaps_run(lcmaps_t *lcmaps) { |
586 |
int rc=0,rc2=0; |
587 |
|
588 |
/* init lcmaps */ |
589 |
if ( (rc=lcmaps->lcmaps_init(lcmaps->logfile)) ) { |
590 |
llerr("lcmaps_init() failed\n"); |
591 |
goto lcmapsrun_closelib; |
592 |
} |
593 |
/* init lcmaps account struct */ |
594 |
if ( (rc=lcmaps->lcmaps_account_info_init(&lcmaps->account)) ) { |
595 |
llerr("lcmaps_account_info_init() failed.\n"); |
596 |
goto lcmapsrun_closelib; |
597 |
} |
598 |
|
599 |
/* Optionally enable/disable voms checking */ |
600 |
if (lcmaps->dovoms==0) |
601 |
lcmaps->lcmaps_disable_voms_attributes_verification(); |
602 |
else if (lcmaps->dovoms==1) |
603 |
lcmaps->lcmaps_enable_voms_attributes_verification(); |
604 |
|
605 |
/* Do actual mapping call */ |
606 |
switch (lcmaps->mode) { |
607 |
case LCMAPS_RETURN_ACCOUNT_FROM_PEM: |
608 |
if ( (rc=lcmaps->lcmaps_return_account_from_pem( |
609 |
lcmaps->cred->pemstring,-1,&lcmaps->account)) ) { |
610 |
llerr("lcmaps_return_account_from_pem() failed.\n"); |
611 |
goto lcmapsrun_clean; |
612 |
} |
613 |
break; |
614 |
case LCMAPS_RETURN_POOLINDEX_WITHOUT_GSI: |
615 |
if ( (rc=lcmaps->lcmaps_return_poolindex_without_gsi( |
616 |
lcmaps->cred->dn, lcmaps->cred->fqans, |
617 |
lcmaps->cred->nfqan, &lcmaps->account)) ) { |
618 |
llerr("lcmaps_return_poolindex_without_gsi() failed.\n"); |
619 |
goto lcmapsrun_clean; |
620 |
} |
621 |
break; |
622 |
case LCMAPS_RETURN_ACCOUNT_WITHOUT_GSI: |
623 |
if ( (rc=lcmaps->lcmaps_return_account_without_gsi( |
624 |
lcmaps->cred->dn, lcmaps->cred->fqans, |
625 |
lcmaps->cred->nfqan, 0, &lcmaps->account)) ) { |
626 |
llerr("lcmaps_return_account_without_gsi() failed.\n"); |
627 |
goto lcmapsrun_clean; |
628 |
} |
629 |
break; |
630 |
} |
631 |
/* terminate lcmaps */ |
632 |
if ( (rc=lcmaps->lcmaps_term()) ) { |
633 |
llerr("lcmaps_term() failed.\n"); |
634 |
goto lcmapsrun_clean; |
635 |
} |
636 |
/* LCMAPS finished succesfully */ |
637 |
rc=0; |
638 |
llnotice("LCMAPS succeeded.\n"); |
639 |
|
640 |
/* Print contents of account */ |
641 |
lcmaps_print_account(&lcmaps->account); |
642 |
|
643 |
lcmapsrun_clean: |
644 |
/* Cleaning and freeing the account structure */ |
645 |
if ( (rc2=lcmaps->lcmaps_account_info_clean(&lcmaps->account)) ) |
646 |
llerr("lcmaps_account_info_clean() failed.\n"); |
647 |
|
648 |
lcmapsrun_closelib: |
649 |
/* Close library */ |
650 |
dlclose(lcmaps->handle); |
651 |
if (lcmaps->helper) |
652 |
dlclose(lcmaps->helper); |
653 |
/* when non-clean function failed: return its rc, otherwise that of clean */ |
654 |
return (rc ? rc : rc2); |
655 |
} |
656 |
|
657 |
/************************************************************************/ |
658 |
/* LCAS FUNCTIONS */ |
659 |
/************************************************************************/ |
660 |
|
661 |
/* Parses the options for LCAS and opens the logfile when needed */ |
662 |
int lcas_set_vars(char *options,lcas_t *lcas) { |
663 |
char *var=options,*value,*end,*pos; |
664 |
|
665 |
/* set defaults */ |
666 |
lcas->rsl=NULL; |
667 |
|
668 |
/* If first char of options is a - it's actually the next main option */ |
669 |
if (options==NULL || options[0]=='-') |
670 |
return 0; |
671 |
|
672 |
do { |
673 |
/* Find end of current var=value pair */ |
674 |
end=strchr(var, ','); |
675 |
if (end!=NULL) end[0]='\0'; |
676 |
/* Find end of variable name */ |
677 |
pos=strchr(var,'='); |
678 |
if (pos==NULL) |
679 |
llerr("Unrecognized element '%s'\n", var); |
680 |
else { |
681 |
pos[0]='\0'; |
682 |
value=pos+1; |
683 |
/* Find the variable */ |
684 |
if (strcmp(var,"debug")==0) |
685 |
setenv("LCAS_DEBUG_LEVEL",value,1); |
686 |
else if (strcmp(var,"db")==0) |
687 |
setenv("LCAS_DB_FILE",value,1); |
688 |
else if (strcmp(var,"rsl")==0) { |
689 |
if ((lcas->rsl=strdup(value))==NULL) { |
690 |
llerr("Cannot strdup() RSL string for LCAS\n"); |
691 |
return 1; |
692 |
} |
693 |
} |
694 |
else if (strcmp(var,"file")==0) { |
695 |
/* Only open when not already linked to stderr */ |
696 |
if (lcas->logfile==NULL) { |
697 |
if ( (lcas->logfile=fopen(value,"a"))==NULL) |
698 |
llwarn("Cannot open %s: %s\n", value,strerror(errno)); |
699 |
} |
700 |
} |
701 |
else |
702 |
llwarn("Unrecognized option '%s'\n",var); |
703 |
/* reset value at pos */ |
704 |
pos[0]='='; |
705 |
} |
706 |
if (end!=NULL) { |
707 |
/* reset value at end */ |
708 |
end[0]=','; |
709 |
/* advance to next option */ |
710 |
var=end+1; |
711 |
} |
712 |
} while (end!=NULL); |
713 |
|
714 |
return 0; |
715 |
} |
716 |
|
717 |
/* Dynamically loads LCAS library and all needed symbols */ |
718 |
int lcas_loadlib(lcas_t *lcas,opts_t *flags) { |
719 |
/* Load the library */ |
720 |
if ( (lcas->handle= |
721 |
dlopen("liblcas.so",RTLD_NOW | RTLD_GLOBAL))==NULL ) { |
722 |
llerr("%s\n",dlerror()); |
723 |
return 1; |
724 |
} |
725 |
return 0; |
726 |
} |
727 |
|
728 |
/* Dynamically loads LCAS library symbols */ |
729 |
int lcas_loadfcies(lcas_t *lcas) { |
730 |
char *err; |
731 |
|
732 |
/* Clean dlerror() */ |
733 |
dlerror(); |
734 |
|
735 |
/* Load functions */ |
736 |
lcas->lcas_init=(int (*)(FILE*)) |
737 |
dlsym(lcas->handle,"lcas_init"); |
738 |
if ( (err=dlerror())!=NULL) |
739 |
goto lcasfcies_failed; |
740 |
lcas->lcas_pem= (int (*)(char*,lcas_request_t)) |
741 |
dlsym(lcas->handle,"lcas_pem"); |
742 |
if ( (err=dlerror())!=NULL) |
743 |
goto lcasfcies_failed; |
744 |
lcas->lcas_term=(int (*)(void)) |
745 |
dlsym(lcas->handle,"lcas_term"); |
746 |
if ( (err=dlerror())!=NULL) |
747 |
goto lcasfcies_failed; |
748 |
|
749 |
return 0; |
750 |
|
751 |
lcasfcies_failed: |
752 |
llerr("%s\n",err); |
753 |
dlclose(lcas->handle); |
754 |
return 1; |
755 |
} |
756 |
|
757 |
/* Loads LCAS library and does a run, for given pemstring and to logfile or |
758 |
* syslog when logfile is NULL and given rsl (=cmd + arguments) */ |
759 |
int lcas_run(lcas_t *lcas) { |
760 |
int rc; |
761 |
|
762 |
/* Do a run */ |
763 |
if ((rc=lcas->lcas_init(lcas->logfile))) { |
764 |
llerr("lcas_init() failed\n"); |
765 |
goto lcasrun_closelib; |
766 |
} |
767 |
if ((rc=lcas->lcas_pem(lcas->cred->pemstring,(lcas_request_t)(lcas->rsl)))){ |
768 |
llerr("lcas_pem() failed.\n"); |
769 |
goto lcasrun_closelib; |
770 |
} |
771 |
if ( (rc=lcas->lcas_term()) ) { |
772 |
llerr("lcas_term() failed.\n"); |
773 |
goto lcasrun_closelib; |
774 |
} |
775 |
llnotice("LCAS succeeded.\n"); |
776 |
|
777 |
lcasrun_closelib: |
778 |
/* Close library */ |
779 |
dlclose(lcas->handle); |
780 |
|
781 |
return rc; |
782 |
} |
783 |
|
784 |
/* Print the version */ |
785 |
void version(void) { |
786 |
printf("%s version: %s\n",prog,VERSION); |
787 |
exit (0); |
788 |
} |
789 |
|
790 |
/* Prints out usage information */ |
791 |
void usage(void) { |
792 |
int uid=(int)getuid(); |
793 |
|
794 |
printf("Usage: %s [options]\n\n",prog); |
795 |
printf("Valid options are:\n" |
796 |
" -h print this help text.\n" |
797 |
" -v print version.\n\n" |
798 |
" -s send output to stderr instead of syslog or file.\n" |
799 |
" -S<facility> use specified syslog facility in case of logging " |
800 |
"to syslog.\n" |
801 |
" -q quiet output (no warnings).\n" |
802 |
" -p<file> read pemstring from given file.\n" |
803 |
" -x<file> set or override X509_USER_PROXY to given file.\n\n" |
804 |
" -V<dir> set or override X509_VOMS_DIR to given dir.\n" |
805 |
" -C<dir> set or override X509_CERT_DIR to given dir.\n\n" |
806 |
" -L[opts] run LCAS with given options: " |
807 |
"<var>=<value>,<var=value>,...\n" |
808 |
" db=<file> set or override LCAS_DB_FILE.\n" |
809 |
" debug=<level> set or override LCAS_DEBUG_LEVEL.\n" |
810 |
" rsl=<string> set rsl string (needs to be quoted).\n" |
811 |
" file=<file> send debug/log output to file instead of " |
812 |
"syslog, ignored\n when -s is specified.\n" |
813 |
"\n -l[opts] run LCMAPS with given options: " |
814 |
"<var>=<value>,<var=value>,...\n" |
815 |
" db=<file> set or override LCMAPS_DB_FILE.\n" |
816 |
" policy=<name> set or override LCMAPS_POLICY_NAME.\n" |
817 |
" debug=<level> set or override LCMAPS_DEBUG_LEVEL.\n" |
818 |
" file=<file> send debug/log output to file instead of " |
819 |
"syslog, ignored\n when -s is specified.\n" |
820 |
" voms={0,1} disable/enable VOMS verification.\n" |
821 |
" mode=<mode> LCMAPS normally extracts all information from " |
822 |
"a PEM string\n" |
823 |
" (i.e. a proxy certificate), but it can be run " |
824 |
"in a mode\n" |
825 |
" \"without_gsi\" where the data such as the DN " |
826 |
"and FQAN are\n" |
827 |
" passed as plain strings, as set on the command " |
828 |
"line.\n" |
829 |
" with -d and -f. Valid modes are:\n" |
830 |
" pem run LCMAPS get_account with pem " |
831 |
"string (default).\n" |
832 |
" nogsi_pi run LCMAPS " |
833 |
"return_poolindex_without_gsi\n" |
834 |
" nogsi_ga run LCMAPS " |
835 |
"return_account_without_gsi\n" |
836 |
" -d<DN> use DN (in without_gsi mode)\n" |
837 |
" -f<FQAN> use FQAN (in without_gsi mode)\n" |
838 |
); |
839 |
printf("\nExample:\n"); |
840 |
printf(" %s -s -p/tmp/x509up_u%d -x/tmp/x509up_u%d \\\n",prog,uid,uid); |
841 |
printf(" -L debug=5,db=/tmp/lcas.db \\\n"); |
842 |
printf(" -l policy=glexec_get_account,debug=5,db=/tmp/lcmaps.db\n"); |
843 |
printf("\nNotes on reproducing gLExec behaviour:\n"); |
844 |
printf("- gLExec uses an LCMAPS policy named 'glexec_get_account'\n"); |
845 |
printf("- the proxy specified with -p is the analog of the "); |
846 |
printf("GLEXEC_CLIENT_CERT.\n"); |
847 |
|
848 |
exit(0); |
849 |
} |
850 |
|
851 |
/* |
852 |
* Initializes the structs, then fills them based on the cmdline args, finally |
853 |
* does some basic checking of the supplied input. |
854 |
*/ |
855 |
void parse_options(int argc, char *argv[], |
856 |
cred_t *cred, opts_t *opts, |
857 |
lcmaps_t *lcmaps, lcas_t *lcas) { |
858 |
extern char *optarg; |
859 |
extern int optind, optopt; |
860 |
int opt,i,fqan_idx; |
861 |
size_t size; |
862 |
char *dummy; |
863 |
|
864 |
/* Get basename, don't rely on basename(3). argv[0] will not contain a |
865 |
* trailing / and will also not be empty... */ |
866 |
dummy=strrchr(argv[0],'/'); |
867 |
prog=( dummy==NULL ? argv[0] : &(dummy[1]) ); |
868 |
|
869 |
/* Set other defaults */ |
870 |
opts->verbose=1; |
871 |
opts->do_lcas=0; |
872 |
opts->do_lcmaps=0; |
873 |
opts->syslog_fac=NULL; |
874 |
|
875 |
cred->nfqan=0; |
876 |
cred->fqans=NULL; |
877 |
cred->pemstring=NULL; |
878 |
cred->dn=NULL; |
879 |
|
880 |
lcmaps->logfile=lcas->logfile=NULL; |
881 |
|
882 |
/* Look for number of FQAN options such that we can initialize the array */ |
883 |
for (i=1; i<argc; i++) { |
884 |
if (strcmp(argv[i],"-f")==0) { |
885 |
cred->nfqan++; |
886 |
i++; /* skip next argument: it's the FQAN */ |
887 |
} |
888 |
} |
889 |
/* Malloc memory for them... */ |
890 |
if (cred->nfqan>0) { |
891 |
size=sizeof(char*)*(cred->nfqan+1); |
892 |
if ( (cred->fqans=malloc(size))==NULL ) { |
893 |
llerr("Cannot malloc %d bytes for fqans\n",(int)size); |
894 |
exit(1); |
895 |
} |
896 |
cred->fqans[cred->nfqan]=NULL; /* NULL-terminate list */ |
897 |
} |
898 |
|
899 |
/* Parse the commandline options */ |
900 |
while ((opt = getopt(argc, argv, ":hvsS:qp:x:V:C:l:L:d:f:")) != -1) { |
901 |
switch (opt) { |
902 |
case 'h': |
903 |
usage(); |
904 |
case 'v': |
905 |
version(); |
906 |
case 's': /* Do not log to file but to stderr */ |
907 |
if (lcmaps->logfile && lcmaps->logfile!=stderr) |
908 |
fclose(lcmaps->logfile); |
909 |
if (lcas->logfile && lcas->logfile!=stderr) |
910 |
fclose(lcas->logfile); |
911 |
lcmaps->logfile=lcas->logfile=stderr; |
912 |
break; |
913 |
case 'S': |
914 |
opts->syslog_fac=optarg; |
915 |
if (opensyslog(opts->syslog_fac)==-1) |
916 |
exit(1); |
917 |
break; |
918 |
case 'q': |
919 |
opts->verbose=0; |
920 |
break; |
921 |
case 'p': |
922 |
if ((cred->pemstring=readproxy(optarg))==NULL) |
923 |
exit(1); |
924 |
break; |
925 |
case 'x': |
926 |
setenv("X509_USER_PROXY",optarg,1); |
927 |
break; |
928 |
case 'V': |
929 |
setenv("X509_VOMS_DIR",optarg,1); |
930 |
break; |
931 |
case 'C': |
932 |
setenv("X509_CERT_DIR",optarg,1); |
933 |
break; |
934 |
case 'l': |
935 |
opts->do_lcmaps=lcmaps_set_vars(optarg,lcmaps)==0 ? 1 : 0; |
936 |
if (optarg[0]=='-') optind--; |
937 |
break; |
938 |
case 'L': |
939 |
opts->do_lcas=lcas_set_vars(optarg,lcas)==0 ? 1 : 0; |
940 |
if (optarg[0]=='-') optind--; |
941 |
break; |
942 |
case 'd': |
943 |
cred->dn = optarg; |
944 |
break; |
945 |
case 'f': |
946 |
cred->fqans[fqan_idx++]=optarg; |
947 |
break; |
948 |
case ':': |
949 |
/* Option did not receive an expected argument (only when last |
950 |
* of line get here, otherwise next option is used as argument), |
951 |
* includes those with optional arguments, i.e. -l and -L */ |
952 |
switch(optopt) { |
953 |
case 'l': |
954 |
lcmaps_set_vars(NULL,lcmaps); |
955 |
opts->do_lcmaps=1; |
956 |
break; |
957 |
case 'L': |
958 |
lcas_set_vars(NULL,lcas); |
959 |
opts->do_lcas=1; |
960 |
break; |
961 |
default: |
962 |
fprintf(stderr, |
963 |
"%s: option requires an argument -- '%c'\n", |
964 |
prog,optopt); |
965 |
fprintf(stderr,"Try `%s -h` for more information.\n", |
966 |
prog); |
967 |
exit(1); |
968 |
} |
969 |
break; |
970 |
case '?': |
971 |
fprintf(stderr,"%s: invalid option -- '%c'\n", prog, optopt); |
972 |
fprintf(stderr,"Try `%s -h` for more information.\n",prog); |
973 |
exit(1); |
974 |
} |
975 |
} |
976 |
|
977 |
/* Print warnings when verbose */ |
978 |
if (opts->verbose) { |
979 |
if (cred->pemstring==NULL) |
980 |
llwarn("Empty pemstring for proxy.\n"); |
981 |
if (getenv("X509_USER_PROXY")==NULL) |
982 |
llwarn("X509_USER_PROXY is not set.\n"); |
983 |
if (opts->do_lcas) { |
984 |
if (lcas->logfile==NULL) { |
985 |
llwarn("LCAS logging will go to syslog"); |
986 |
if (opts->syslog_fac==NULL) |
987 |
fprintf(stderr,".\n"); |
988 |
else |
989 |
fprintf(stderr,", using facility %s.\n",opts->syslog_fac); |
990 |
} |
991 |
if (getenv("LCAS_DB_FILE")==NULL) |
992 |
llwarn("using LCAS default db file.\n"); |
993 |
} |
994 |
if (opts->do_lcmaps) { |
995 |
if (lcmaps->logfile==NULL) { |
996 |
llwarn("LCMAPS logging will go to syslog"); |
997 |
if (opts->syslog_fac==NULL) |
998 |
fprintf(stderr,".\n"); |
999 |
else |
1000 |
fprintf(stderr,", using facility %s.\n",opts->syslog_fac); |
1001 |
} |
1002 |
if (getenv("LCMAPS_DB_FILE")==NULL) |
1003 |
llwarn("using LCMAPS default db file.\n"); |
1004 |
if (getenv("LCMAPS_POLICY_NAME")==NULL) |
1005 |
llwarn("using LCMAPS default policy name.\n"); |
1006 |
if ( (lcmaps->mode == LCMAPS_RETURN_ACCOUNT_WITHOUT_GSI || |
1007 |
lcmaps->mode == LCMAPS_RETURN_POOLINDEX_WITHOUT_GSI) && |
1008 |
cred->dn == NULL) |
1009 |
llwarn("running without GSI with NULL DN string.\n"); |
1010 |
} |
1011 |
} |
1012 |
} |
1013 |
|
1014 |
/************************************************************************/ |
1015 |
/* MAIN() FUNCTION */ |
1016 |
/************************************************************************/ |
1017 |
|
1018 |
/* Main() */ |
1019 |
int main(int argc, char *argv[]) { |
1020 |
int rc=0; |
1021 |
|
1022 |
lcas_t lcas; |
1023 |
lcmaps_t lcmaps; |
1024 |
opts_t opts; |
1025 |
cred_t cred; |
1026 |
|
1027 |
/* Initialize LCMAPS and LCAS structs */ |
1028 |
lcmaps.opts=lcas.opts=&opts; |
1029 |
lcmaps.cred=lcas.cred=&cred; |
1030 |
|
1031 |
/* Parse cmdline input and fill cred, opts and lcmaps/lcas structs */ |
1032 |
parse_options(argc,argv,&cred,&opts,&lcmaps,&lcas); |
1033 |
|
1034 |
/* Check if we have something to do... */ |
1035 |
if (opts.do_lcas==0 && opts.do_lcmaps==0) { |
1036 |
llnotice("Nothing to do, see %s -h for valid options.\n",prog); |
1037 |
return 0; |
1038 |
} |
1039 |
|
1040 |
/* Do LCAS when requested */ |
1041 |
if (opts.do_lcas) { |
1042 |
rc=(lcas_loadlib(&lcas,&opts) || |
1043 |
lcas_loadfcies(&lcas) || |
1044 |
lcas_run(&lcas)); |
1045 |
if (rc!=0) |
1046 |
llerr("LCAS failed.\n"); |
1047 |
if (lcas.rsl) |
1048 |
free(lcas.rsl); |
1049 |
} |
1050 |
|
1051 |
/* Do LCMAPS when requested */ |
1052 |
if (opts.do_lcmaps) { |
1053 |
rc=(lcmaps_loadlib(&lcmaps, &opts) || |
1054 |
lcmaps_loadfcies(&lcmaps) || |
1055 |
lcmaps_run(&lcmaps)); |
1056 |
if (rc!=0) |
1057 |
llerr("LCMAPS failed.\n"); |
1058 |
} |
1059 |
|
1060 |
free(cred.pemstring); |
1061 |
free(cred.fqans); |
1062 |
|
1063 |
return rc; |
1064 |
} |