4 * Copyright (c) 2004 The Regents of the University of Michigan.
7 * Olga Kornievskaia <aglo@umich.edu>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/types.h>
45 #include "nfsidmap_internal.h"
48 #include <voms_apic.h>
50 #include <prima_logger.h>
51 #include <prima_soap_client.h>
52 #include <prima_saml_support.h>
54 #define DEFAULT_PRIMA_CONF_LOCATION "/etc/grid-security/prima-authz.conf"
55 #define DEFAULT_VOMSDIR "/etc/grid-security/vomsdir"
56 #define DEFAULT_CADIR "/etc/grid-security/certificates"
57 #define X509_DN_SIZE 1024
59 //#define DEBUG_PRINT_VOMS
61 #define USING_TEST_PROGRAM
62 #ifdef USING_TEST_PROGRAM
63 nfs4_idmap_log_function_t idmap_log_func
= printf
;
64 int idmap_verbosity
= 10;
68 * GUMS Translation Methods
72 /* global variables. voms/gums configuration attributes*/
73 static char prima_conf
[] = DEFAULT_PRIMA_CONF_LOCATION
;
74 typedef struct _plugin_config_params
{
75 char *saml_schema_dir
;
80 char *gums_server_location
;
82 } plugin_config_params
;
83 plugin_config_params conf
;
86 static void my_VOMS_Delete(struct voms
*v
)
96 for (i
= 0; v
->fqan
[i
] != NULL
; i
++)
103 static struct voms
*my_VOMS_Copy(struct voms
*v
, int *err
)
108 cv
= calloc(1, sizeof(struct voms
));
111 cv
->user
= strdup(v
->user
);
112 if (cv
->user
== NULL
)
114 cv
->server
= strdup(v
->server
);
115 if (cv
->server
== NULL
)
117 for (i
= 0; v
->fqan
[i
] != NULL
; i
++) {
118 if (v
->fqan
[i
] == NULL
)
121 cv
->fqan
= calloc(i
+1, sizeof(char *));
122 if (cv
->fqan
== NULL
)
125 for (i
= 0; v
->fqan
[i
] != NULL
; i
++) {
126 cv
->fqan
[i
] = strdup(v
->fqan
[i
]);
127 if (cv
->fqan
[i
] == NULL
)
140 #ifdef DEBUG_PRINT_VOMS
141 void printvoms(struct voms
*v
)
145 printf("SIGLEN: %d\nUSER: %s\n", v
->siglen
, v
->user
);
146 printf("UCA: %s\nSERVER: %s\n", v
->userca
, v
->server
);
147 printf("SCA: %s\nVO: %s\n", v
->serverca
, v
->voname
);
148 printf("URI: %s\nDATE1: %s\n", v
->uri
, v
->date1
);
149 printf("DATE2: %s\n", v
->date2
);
156 printf("%*s\n", v
->datalen
- 10, v
->custom
);
161 printf("GROUP: %s\nROLE: %s\nCAP: %s\n",v
->std
[j
]->group
,
162 v
->std
[j
]->role
,v
->std
[j
]->cap
);
168 void print(struct vomsdata
*d
)
170 struct voms
**vo
= d
->data
;
176 printf("%d *******************************************\n",k
);
181 printf("WORKVO: %s\n", d
->workvo
);
184 printf("EXTRA: %s\n", d
->extra_data
);
188 static void free_plugin_config_params()
190 if (conf
.saml_schema_dir
)
191 free(conf
.saml_schema_dir
);
192 conf
.saml_schema_dir
= NULL
;
193 if (conf
.server_cert
)
194 free(conf
.server_cert
);
195 conf
.server_cert
= NULL
;
197 free(conf
.server_key
);
198 conf
.server_key
= NULL
;
204 conf
.voms_dir
= NULL
;
207 static int validate_plugin_config_params()
209 if (conf
.saml_schema_dir
== NULL
||
210 conf
.server_cert
== NULL
||
211 conf
.server_key
== NULL
||
212 conf
.gums_server_location
== NULL
)
215 if (conf
.ca_dir
== NULL
) {
216 conf
.ca_dir
= strdup(DEFAULT_CADIR
);
217 if (conf
.ca_dir
== NULL
)
220 if (conf
.voms_dir
== NULL
) {
221 conf
.voms_dir
= strdup(DEFAULT_VOMSDIR
);
222 if (conf
.voms_dir
== NULL
)
228 static int gums_init(void)
232 char buf
[512], type
[128], value
[256];
233 char *alt_conf
= NULL
;
235 alt_conf
= conf_get_str("GUMS", "Conf_File");
236 if (alt_conf
== NULL
)
237 f
= fopen(prima_conf
, "r");
239 f
= fopen(alt_conf
, "r");
243 while (fgets(buf
, 512, f
)) {
245 while(buf
[i
] == ' ' || buf
[i
] == '\t')
247 if (buf
[i
] == '#' || buf
[i
] == '\0' || buf
[i
] == '\n')
249 if (sscanf(&buf
[i
], "%127s%255s",type
,value
) < 2) {
250 IDMAP_LOG(0, ("ERROR: malformed line: %s\n", &buf
[i
]));
253 IDMAP_LOG(1, ("PRIMA conf: type=%s value=%s\n", type
, value
));
254 if (strncmp(type
, "imsContact", 10) == 0) {
255 conf
.gums_server_location
= strdup(value
);
256 } else if (strncmp(type
, "serviceCert", 11) == 0) {
257 conf
.server_cert
= strdup(value
);
258 } else if (strncmp(type
, "serviceKey", 10) == 0) {
259 conf
.server_key
= strdup(value
);
260 } else if (strncmp(type
, "caCertDir", 9) == 0) {
261 conf
.ca_dir
= strdup(value
);
262 } else if (strncmp(type
, "samlSchemaDir", 13) == 0) {
263 conf
.saml_schema_dir
= strdup(value
);
264 } else if (strncmp(type
, "logLevel", 8) == 0) {
265 if (strncmp(value
, "debug", 5) == 0)
266 conf
.saml_log_level
= PRIMA_LOG_DEBUG
;
267 else if (strncmp(value
, "error", 5) == 0)
268 conf
.saml_log_level
= PRIMA_LOG_ERROR
;
269 else if (strncmp(value
, "none", 4) == 0)
270 conf
.saml_log_level
= PRIMA_LOG_NONE
;
272 conf
.saml_log_level
= PRIMA_LOG_INFO
;
276 if (validate_plugin_config_params() != 0)
284 free_plugin_config_params();
289 static int retrieve_attributes(X509
*cert
, STACK_OF(X509
) *cas
,
292 int ret
= -1, err
= 0;
293 struct vomsdata
*vd
= NULL
;
295 vd
= VOMS_Init(conf
.voms_dir
, conf
.ca_dir
);
297 IDMAP_LOG(0, ("VOMS_Init failed\n"));
300 ret
= VOMS_Retrieve(cert
, cas
, RECURSE_CHAIN
, vd
, &err
);
303 err_msg
= VOMS_ErrorMessage(vd
, err
, NULL
, 0);
304 if (err
== VERR_NOEXT
)
307 IDMAP_LOG(0, ("VOMS error %s\n", err_msg
));
311 #ifdef DEBUG_PRINT_VOMS
314 v
= VOMS_DefaultData(vd
, &err
);
315 if (err
== VERR_NONE
) {
316 #ifdef DEBUG_PRINT_VOMS
318 while (v
->fqan
[i
] != NULL
)
319 IDMAP_LOG(1, ("user's fqan: %s\n", v
->fqan
[i
++]));
322 v2
= my_VOMS_Copy(v
, &err
);
324 v2
= VOMS_Copy(v
, &err
);
327 IDMAP_LOG(0, ("VOMS_Copy failed err=%d\n", err
));
340 static int get_server_dn(unsigned char **server_dn
)
345 char dn
[X509_DN_SIZE
];
347 tmp
= BIO_new(BIO_s_file());
351 ret
= BIO_read_filename(tmp
, conf
.server_cert
);
357 cert
= (X509
*) PEM_read_bio_X509(tmp
, NULL
, NULL
, NULL
);
361 X509_NAME_oneline(X509_get_subject_name(cert
), dn
, sizeof(dn
));
363 *server_dn
= strdup(dn
);
364 if (*server_dn
== NULL
)
377 static int create_saml_request(char *dn
, struct voms
*attrs
, char **saml_req
)
381 unsigned char *server_dn
= NULL
;
382 prima_saml_fqans fqans
;
384 IDMAP_LOG(2, ("create_saml_request start\n"));
385 ret
= initPrimaSAMLFQANs(&fqans
);
387 IDMAP_LOG(0, ("initPrimaSAMLFQANs failed with %d\n", ret
));
392 for (i
= 0; attrs
->fqan
[i
] != NULL
; i
++) {
393 ret
= addPrimaSAMLFQAN(&fqans
, attrs
->server
, attrs
->fqan
[i
]);
394 IDMAP_LOG(1, ("addPrimaSAMLFQAN returned %d\n", ret
));
398 IDMAP_LOG(1, ("No VOMS attributes present in the cert\n"));
400 if (get_server_dn(&server_dn
) != 0)
402 req
= createSAMLQueryAndRequest(server_dn
, dn
, &fqans
);
404 IDMAP_LOG(0, ("createSAMLQueryAndRequest failed to create "
408 IDMAP_LOG(1, ("SAML Request %s\n", req
));
413 cleanupPrimaSAMLFQANs(&fqans
);
418 IDMAP_LOG(2, ("create_saml_request returning %d\n", ret
));
422 static int process_parameters(extra_mapping_params
**ex
, X509
**user_cert
,
423 STACK_OF(X509
) **user_chain
)
427 X509
*cert
= NULL
, *x
;
428 STACK_OF(X509
) *chain
= NULL
;
431 if (ex
[0]->content_type
!= X509_CERT
)
434 /* get user's x509 certificate */
436 cert
= d2i_X509(NULL
, &p
, ex
[0]->content_len
);
440 /* get user's other certificates */
441 chain
= sk_X509_new_null();
444 for (i
= 1; ex
[i
] != NULL
; i
++) {
445 if (ex
[i
]->content_type
!= X509_CERT
)
448 x
= d2i_X509(NULL
, &p
, ex
[i
]->content_len
);
451 sk_X509_push(chain
, x
);
463 sk_X509_pop_free(chain
, X509_free
);
474 static int translate_to_uid(char *local_uid
, uid_t
*uid
, uid_t
*gid
)
477 struct passwd
*pw
= NULL
;
478 struct pwbuf
*buf
= NULL
;
479 size_t buflen
= sysconf(_SC_GETPW_R_SIZE_MAX
);
481 buf
= malloc(sizeof(*buf
) + buflen
);
485 ret
= getpwnam_r(local_uid
, &buf
->pwbuf
, buf
->buf
, buflen
, &pw
);
487 IDMAP_LOG(0, ("getpwnam: name %s not found\n", local_uid
));
500 static int translate_to_gid(char *local_gid
, uid_t
*gid
)
502 struct group
*gr
= NULL
;
505 size_t buflen
= sysconf(_SC_GETGR_R_SIZE_MAX
);
509 buf
= malloc(buflen
);
513 ret
= -getgrnam_r(local_gid
, &grbuf
, buf
, buflen
, &gr
);
514 if (gr
== NULL
&& !ret
)
516 if (ret
== -ERANGE
) {
520 } while (ret
== -ERANGE
);
534 static int gums_gss_princ_to_ids(char *secname
, char *princ
,
535 uid_t
*uid
, uid_t
*gid
,
536 extra_mapping_params
**ex
)
538 int ret
= -1, size
, i
;
540 STACK_OF(X509
) *cas
= NULL
;
541 char dn
[X509_DN_SIZE
];
542 struct voms
*attrs
= NULL
;
543 char *saml_req
= NULL
, *saml_resp
= NULL
;
545 char *local_uid
= NULL
, *local_gid
= NULL
, *p
;
547 /* accept only spkm3 translations */
548 if (strcmp(secname
, "spkm3"))
551 /* must supply either a DN and/or at least 1 binary blob */
552 if (princ
== NULL
&& (ex
== NULL
|| (ex
&& ex
[0] == NULL
)))
555 /* process extra parameters */
556 if (process_parameters(ex
, &cert
, &cas
) != 0)
559 IDMAP_LOG(1, ("Processing name translation of client\n"));
560 X509_NAME_oneline(X509_get_subject_name(cert
), dn
, sizeof(dn
));
561 IDMAP_LOG(1, ("DN=%s\n", dn
));
562 size
= sk_X509_num(cas
);
563 IDMAP_LOG(1, ("Including following CAs (%d)\n", size
));
564 for (i
=0; i
< size
; i
++) {
565 X509_NAME_oneline(X509_get_subject_name(sk_X509_value(cas
, i
)),
567 IDMAP_LOG(1, ("DN=%s\n", dn
));
570 /* retrieve VOMS attributes */
571 if (retrieve_attributes(cert
, cas
, &attrs
) != 0)
574 X509_NAME_oneline(X509_get_subject_name(cert
), dn
, sizeof(dn
));
576 /* initialize SAML library */
577 if (initPrimaSAMLSupport(conf
.saml_schema_dir
,
578 conf
.saml_log_level
) != 0) {
579 IDMAP_LOG(0, ("initPrimaSAMLSupport failed\n"));
583 /* create SAML request */
584 if (create_saml_request(dn
, attrs
, &saml_req
) != 0)
587 /* contact GUMS server */
588 saml_resp
= queryIdentityMappingService(conf
.gums_server_location
,
589 saml_req
, conf
.server_cert
, conf
.server_key
,
591 if (saml_resp
!= NULL
) {
592 saml_result
= processResponse(saml_resp
, saml_req
, &local_uid
,
594 IDMAP_LOG(1, ("processResponse returned %d\n", saml_result
));
595 if (saml_result
|| local_uid
== NULL
) {
596 IDMAP_LOG(0, ("processResponse failed to return "
601 IDMAP_LOG(1, ("GUMS returned uid=%s gid=%s\n", local_uid
,
605 /* translate account name to uid */
606 if (translate_to_uid(local_uid
, uid
, gid
))
609 if (translate_to_gid(local_gid
, gid
))
618 sk_X509_pop_free(cas
, X509_free
);
622 my_VOMS_Delete(attrs
);
633 cleanupPrimaSAMLSupport();
638 struct trans_func gums_trans
= {
641 .princ_to_ids
= gums_gss_princ_to_ids
,
646 .gss_princ_to_grouplist
= NULL
,
649 struct trans_func
*libnfsidmap_plugin_init()
651 return (&gums_trans
);
654 #ifdef USING_TEST_PROGRAM
655 static STACK_OF(X509
) *load_chain(char *certfile
)
657 STACK_OF(X509_INFO
) *sk
=NULL
;
658 STACK_OF(X509
) *stack
=NULL
, *ret
=NULL
;
663 if (!(stack
= sk_X509_new_null())) {
664 printf("memory allocation failure\n");
668 if (!(in
=BIO_new_file(certfile
, "r"))) {
669 printf("error opening the file, %s\n",certfile
);
673 /* This loads from a file, a stack of x509/crl/pkey sets */
674 if (!(sk
=(STACK_OF(X509_INFO
) *)PEM_X509_INFO_read_bio(in
,NULL
,NULL
,NULL
))) {
675 /* if (!(sk=PEM_X509_read_bio(in,NULL,NULL,NULL))) { */
676 printf("error reading the file, %s\n",certfile
);
680 /* scan over it and pull out the certs */
681 while (sk_X509_INFO_num(sk
)) {
682 /* skip first cert */
684 xi
=sk_X509_INFO_shift(sk
);
689 xi
=sk_X509_INFO_shift(sk
);
690 if (xi
->x509
!= NULL
) {
691 sk_X509_push(stack
,xi
->x509
);
696 if (!sk_X509_num(stack
)) {
697 printf("no certificates in file, %s\n",certfile
);
704 sk_X509_INFO_free(sk
);
708 void create_params(X509
*cert
, STACK_OF(X509
) *cas
,
709 extra_mapping_params
***ret_params
)
711 int len
= 0, i
, size
= 0;
712 unsigned char *p
, *buf
= NULL
;
713 extra_mapping_params
**params
= NULL
;
717 size
= sk_X509_num(cas
);
718 params
= malloc((size
+2)*sizeof(extra_mapping_params
*));
719 params
[size
+1] = NULL
;
721 /* 1st element is user's certificate */
722 len
= i2d_X509(cert
, NULL
);
723 p
= buf
= malloc(len
);
725 params
[0] = malloc(sizeof(extra_mapping_params
));
726 params
[0]->content_type
= X509_CERT
;
727 params
[0]->content
= buf
;
728 params
[0]->content_len
= len
;
730 /* add other certificates to the array */
731 for (i
= 0; i
< size
; i
++) {
732 x
= sk_X509_value(cas
, i
);
733 params
[i
+1] = malloc(sizeof(extra_mapping_params
));
734 len
= i2d_X509(x
, NULL
);
735 p
= buf
= malloc(len
);
737 params
[i
+1]->content_type
= X509_CERT
;
738 params
[i
+1]->content
= buf
;
739 params
[i
+1]->content_len
= len
;
741 *ret_params
= params
;
746 int uid
, gid
, ret
, i
;
747 extra_mapping_params
**params
= NULL
;
749 X509
*cert
= NULL
, *x
;
750 STACK_OF(X509
) *cas
= NULL
;
751 unsigned char *proxy_file
;
755 proxy_file
= getenv("X509_USER_PROXY");
756 if (proxy_file
== NULL
) {
757 fprintf(stderr
, "X509_USER_PROXY is not set\n");
760 tmp
= BIO_new(BIO_s_file());
761 BIO_read_filename(tmp
, proxy_file
);
762 cert
= (X509
*) PEM_read_bio_X509(tmp
, NULL
, NULL
, NULL
);
763 cas
= load_chain(proxy_file
);
764 create_params(cert
, cas
, ¶ms
);
765 ret
= gums_gss_princ_to_ids("spkm3", NULL
, &uid
, &gid
, params
);
766 fprintf(stderr
, "gums_gss_princ_to_ids returns %d uid=%d gid=%d\n",
774 sk_X509_pop_free(cas
, X509_free
);
776 free_plugin_config_params();
779 for (i
=0; params
[i
] != NULL
; i
++) {
780 free(params
[i
]->content
);