diff --git a/README/README.AUTH b/README/README.AUTH new file mode 100644 index 0000000000000000000000000000000000000000..f9ebd86a2178172b0f6867296724ad159c293be3 --- /dev/null +++ b/README/README.AUTH @@ -0,0 +1,382 @@ + +Authentication to rootd/proofd servers +====================================== + +The rootd/proofd daemon servers accept 6 methods of authentication, listed +in Table 1, together with their internal codes and short names. +Method 5 (rfio) is provided for fast access when security is not an issue. +Method 0 can be 'secured' by using a session public key, automatically +generated, which allows to avoid direct exchange of passwords; since this +may slow down the process, it can be switched of if not needed. + + Table 1: authentication methods available + +-------------------------------------------------------------------------+ + | Method | code | short name | in .rootrc | Secure | + |-------------------------------------------------------------------------| + | (user,password) clear | 0 | clear | Clear | No/Yes | + | (user,password) SRP | 1 | srp | SRP | Yes | + | Kerberos V | 2 | krb5 | Krb5 | Yes | + | Globus GSSAPI | 3 | globus | Globus | Yes | + | SSH | 4 | ssh | Ssh | Yes | + | (uid,gid) | 5 | rfio | Rfio | No | + +-------------------------------------------------------------------------+ + +A specific method can be requested via the .rootrc family files (in order of +priority $HOME/.rootrc, /etc/root/system.rootrc and +$ROOTSYS/etc/system.rootrc), the file $HOME/.authrootrc (superseded by the +variable AUTHROOTRC, if defined), or during the root session as explained +below. + +Controlling access +================== + +Upon request of access, rootd/proofd build a list of secure methods available +locally; this is based on the compilation flags for SRP, Kerberos and Globus, +and on the running of the 'sshd' daemon for SSH. By default the two servers +accept authentications only via the methods in such a list. However the +administrator of the servers can grant access via other authentication methods +by defining a host specific list in etc/rpdauth.allow (see the example for this +file under etc for more details). + +Negotiation +=========== + +Simple negotiation is supported as follows. The client sends the preferred +method (the first one in the list, see below) to the server; if this is among +the methods accepted by the server (not necessarily the one preferred by the +server) authentication is attempted. In the case the attempt is unsuccessful, +the server sends back the list of the remaining methods accepted (if any); the +client compares the server list with its own list of remaining methods and +makes a new attempt if the overlap of the two lists is not empty; and so on. + +Slave/Data servers authentication during a PROOF session +======================================================== + +During a PROOF session there is the potential problem of Master/Slave or +Slave/Data_Server authentication. For slaves, the list of methods to be tried +is specified in the proof.conf file as a list of methods short names. However, +before build the corresponding entry in THostAuth (see below) TProof checks +that the method can be applied, i.e. that there valid credentials. The way +these are transmitted depends on the method and on the Client/Master +authentication method. + + * Clear: to authenticate 'clear' to slaves, the master needs the relevant + entry in the .netrc or .rootnetrc files; however, if the + client/master authentication was also 'clear', the password is + already present on the master process and is used for later clear + authentications. + + * SRP: to authenticate 'SRP' to slaves, the master needs the relevant entry + in the .netrc or .rootnetrc files; the syntax is the same as for + 'clear' authentication with the keyword 'secure' at the place of + 'machine' + + * Krb5 to authenticate 'Kerberos' to slaves, the master needs the Kerberos + tokens; these must be initialized by hand on the master, since for + the time being, ticket forwarding has not been implemented. + + * Globus to authenticate 'Globus' to slaves, the master needs globus + credentials; this is possible (and automatic) only if the + client/master authentication was also 'globus' + + * SSH to authenticate 'SSH' to slaves, the master needs the relevant + private key files in $HOME/.ssh (on the master). + + * Rfio to authenticate 'Rfio' to slaves, the user must have the same + (uid,gid) on master and slaves. + +Negotiation is active also between master and slaves, so it is a good habit to +ask for rfio first to accelerate as possible the authentication process. + +The method actually used is listed by gProof->Print(). + +If the slaves need to access data servers which are not part of the proof +cluster, the login info vis-a-vis of these may be specified with the proofdserv +card in the .authrootrc files (see below and etc/example.authrootrc for +details); the collected information is then transmitted to all the active +slaves upon creation. + + +Entries in .rootrc +================== + +The authentication related entries in the .rootrc family of files define +directives applying to all remote host and all remote accounts. The available +directives are the following: + +* General switchings + + Rootd.Authentication: <code> Proofd.Authentication <code> + + These variables specify the default method to be attempted for remote + authentication for rootd and proofd respectively; <code> is the internal code + given in Table 1; these directives supersede the default ('ssh' for normal + users and 'clear' for anonymous users). + +* The <method>.Login directives specify the default login for the method: + + Clear.Login, SRP.Login, Ssh.Login, Rfio.Login: <username> (e.g.: qwerty) + Krb5.Login: <principal> (e.g.: qwerty@THIS.DOM.AIN) + Globus.Login: cd:<dir_with_my_certs> cf:<my_cert_file> \ + kf:<my_key_file> ad:<dir_with_CA_certs> + +* The <method>.LoginPrompt directives specify whether root should prompt you + for the login (with default the login specified via <method>.Login; possible + values are 0 or no for no prompt, 1 or yes to have the prompt; valid + examples: + + Clear.LoginPrompt: 0 + Krb5.LoginPrompt: 1 + Globus.LoginPrompt: no + Ssh.LoginPrompt: yes + + Default is no prompt. + + For anonymous 'clear' login, setting off the Login.Prompt implies automatic + generation of the password in the form <user>@<local_host_fqdn>, where <user> + is obtained from the variable USER or from ' getpwuid(getuid())->pw_name '. + +* The <method>.ReUse directives specify whether root reuse valid authentication + once established; possible values are '0' or 'no' for OFF, '1' or 'yes' for ON. + When this option is active, the client generates a session RSA key pair and + transmits the public key to the server; the server generates a session 'token' + which can be used by the client for later access to the server. + This facility is implemented for all methods except Rfio (for which there would + be no advantage); it is switched ON by default for Clear, Globus and Ssh,since + it allows to speed up significantly repeated access to the same server. + For SRP and Krb5 it is implemented but switched OFF by default, since it does + not improve on authentication time (especially for Krb5). + + Clear.ReUse: yes + SRP.ReUse: no + Krb5.ReUse: 0 + Globus.ReUse: yes + Ssh.ReUse: 1 + +* Other directives + + * Clear + + * To secure password exchange set (this is the default) + + Clear.Crypt 1 + + A session key pair is generated and used to encrypt the password hash to + be communicated to the server. + + * globus + + * to change the duration in hours of globus credentials (default is 12) use + Globus.ProxyDuration: <hours> + + * to change the number of bits in the key (default 1024) + Globus.ProxyKeyBits: <bits> + where <bits> is 512 or 1024 or 2048 or 4096 + + * ssh + + * to change the path with the 'ssh' executable + Ssh.ExecDir <new_path> + (the executable will then be <new_path>/ssh) + + +.authrootrc +=========== + +The .authrootrc file allow to specify host and user specific instructions; all +the possibilities are explained in etc/example.authrootrc. The information read +is used to instantiate THostAuth objects; these can be modified during the root +session as explained in the next session. + + +Modifying/Adding authentication info during the session +======================================================= + +Remote authentication in root is controlled by the TAuthenticate class; +TNetFile, TFTP and TSlave create a TAuthenticate object before proceeding to +authentication. + +Authentication is (host,user) specific. The dedicated class THostAuth contains +the information for a specific (host,user): + + + remote host FQDN + + user name + + number of available methods n + + method internal codes (dimension n) + + login info for each method (dimension n) + + list of established authentication + +The available methods are listed in order of preference: the first one is the +one preferred, the others are tried in turn upon failure of the previous one, +and if accepted by the remote daemon (see Negotiation below). + +THostAuth objects are instantiated by TAuthenticate upon creation based on the +information found in the files mentioned above. A set of methods are available +in the TAuthenticate and THostAuth classes to display/modify/create THostAuth +classes: + + * void TAuthenticate::PrintHostAuth() + + Prints the content of the instantiated THostAuth objects + + Example: + + root [1] TAuthenticate::PrintHostAuth() + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::Print>: + Host:pcepsft43.cern.ch - User:ganis - # of available methods:5 + Info in <THostAuth::Print>: + Method: 3 Details:pt:no cd:~/.globus cf:usercert.pem kf:userkey.pem ad:certificates + Info in <THostAuth::Print>: + Method: 4 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 0 Details:pt:no us:ganis + Info in <THostAuth::Print>: + Method: 1 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 5 Details:pt:yes us:ganis + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::PrintEstablished>: +------------------------------------------------------------------+ + Info in <THostAuth::PrintEstablished>: + Host:pcepsft43.cern.ch - Number of Established Authentications: 1 + Info in <TAuthDetails::PrintEstblshd>: + Method:1 OffSet:278 Login:ganis Prompt:0 ReUse:1 + Info in <TAuthDetails::PrintEstblshd>: + Details:pt:0 ru:1 us:ganis + Info in <THostAuth::PrintEstablished>: +------------------------------------------------------------------+ + root [2] + + The method THostAuth::PrintEstablished is also called, displaying the + relevant info about successful authentications saved in TAuthDetails (see + below for details about TAuthDetails). + + * THostAuth *TAuthenticate::GetHostAuth("<host_fqdn>","<user>") + + Returns a pointer to the THostAuth object pertaining to (host,user) if it + exist, 0 otherwise. + + Example: + + root [2] THostAuth *ha = TAuthenticate::GetHostAuth("pcepsft43.cern.ch","ganis") + root [3] printf("ha: 0x%x\n",(int)ha); + ha: 0x88df970 + root [4] THostAuth *ha = TAuthenticate::GetHostAuth("der.mit.ow","scruno") + root [5] printf("ha: 0x%x\n",(int)ha); + ha: 0x0 + root [6] + + * void TAuthenticate::ReadAuthRc("<host_fqdn>","<user>") + + Loads information about (host,user) from .authrootrc or from the defaults in + .rootrc + + * void TAuthenticate::RemoveHostAuth(THostAuth *ha) + + Removes and destroys the THostAuth object pointed by ha from the static list + in TAuthenticate + + * void THostAuth::Print() + + Prints the information contained in this THostAuth object + + Example: + + root [7] THostAuth *ha = TAuthenticate::GetHostAuth("pcepsft43.cern.ch","ganis") + root [8] ha->Print() + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::Print>: + Host:pcepsft43.cern.ch - User:ganis - # of available methods:5 + Info in <THostAuth::Print>: + Method: 3 Details:pt:no cd:~/.globus cf:usercert.pem kf:userkey.pem ad:certificates + Info in <THostAuth::Print>: + Method: 4 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 1 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 5 Details:pt:yes us:ganis + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + root [9] + + * void THostAuth::AddMethod(<code>,<login_inf>) + + Add a new method (internal code <code>, login information <login_info>) at + the end of the list of available methods + + Example (with respect to above): + + root [9] ha->AddMethod(0,"no us:ganis") + root [10] ha->Print() + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::Print>: + Host:pcepsft43.cern.ch - User:ganis - # of available methods:4 + Info in <THostAuth::Print>: + Method: 3 Details:pt:no cd:~/.globus cf:usercert.pem kf:userkey.pem ad:certificates + Info in <THostAuth::Print>: + Method: 4 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 1 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 5 Details:pt:yes us:ganis + Info in <THostAuth::Print>: + Method: 0 Details:pt:no us:ganis + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + root [11] + + * void THostAuth::RemoveMethod(<code>) + + Removes method with internal code <code> from the list of available methods + + Example (with respect to above): + + root [9] ha->RemoveMethod(5) + root [10] ha->Print() + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::Print>: + Host:pcepsft43.cern.ch - User:ganis - # of available methods:4 + Info in <THostAuth::Print>: + Method: 3 Details:pt:no cd:~/.globus cf:usercert.pem kf:userkey.pem ad:certificates + Info in <THostAuth::Print>: + Method: 4 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 1 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 0 Details:pt:no us:ganis + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + root [11] + + * void THostAuth::SetDetails(<code>,<login_inf>) + + Changes login info for method with internal code <code> to <login_info>; if + it does not exist, add a this as new method. + + Example (with respect to above): + + root [11] ha->SetDetails(4,"pt:no ru:1 us:gganis") + root [12] ha->Print() + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::Print>: + Host:pcepsft43.cern.ch - User:ganis - # of available methods:4 + Info in <THostAuth::Print>: + Method: 3 Details:pt:no cd:~/.globus cf:usercert.pem kf:userkey.pem ad:certificates + Info in <THostAuth::Print>: + Method: 4 Details:pt:no ru:1 us:gganis + Info in <THostAuth::Print>: + Method: 1 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 0 Details:pt:no us:ganis + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + root [13] + + * void THostAuth::SetFirst(<code>) + + Set method with internal code <code> as the preferred one, if it exists. + + Example (with respect to above): + + root [13] ha->SetFirst(1) + root [14] ha->Print() + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + Info in <THostAuth::Print>: + Host:pcepsft43.cern.ch - User:ganis - # of available methods:4 + Info in <THostAuth::Print>: + Method: 1 Details:pt:no ru:1 us:ganis + Info in <THostAuth::Print>: + Method: 3 Details:pt:no cd:~/.globus cf:usercert.pem kf:userkey.pem ad:certificates + Info in <THostAuth::Print>: + Method: 4 Details:pt:no ru:1 us:gganis + Info in <THostAuth::Print>: + Method: 0 Details:pt:no us:ganis + Info in <THostAuth::Print>: +------------------------------------------------------------------+ + root [15] + + * void THostAuth::SetFirst(<code>,<login_inf>) + + Set method with internal code <code> as the preferred one, and changes the + login information to <login_inf>. If it does not exist, add a new method in + first position. + + * void THostAuth::ReOrder(nmet,meths) + + Reorder the list of the available methods in such a way that the first nmet + methods are the ones listed in meths[nmet]. + + + +TAuthDetails +============ + +The class TAuthDetails contains the relevant details about a successful +authentication to be used to speed up access to the same (host,user) entity +during the same session. Each THostAuth contains a list of TAuthDetails objects +pertaining to {host,user) + + + + + + diff --git a/README/README.GLOBUS b/README/README.GLOBUS new file mode 100644 index 0000000000000000000000000000000000000000..17aee0a18687eada625ada97560d9b027466ed2d --- /dev/null +++ b/README/README.GLOBUS @@ -0,0 +1,232 @@ + +Using Globus certificates to authenticate to a remote rootd/proofd server +========================================================================= + +To use Globus certificates for remote authentication, the Globus Tool Kit +should be installed both in client and server machines and ROOT should be +compiled with the relevant flags set (see below). + +Globus Authentication has been tested for the moment only on Linux. + +1) Globus Tool Kit (GTK) Version + + The interface has been developed using GTK version 2.2.3 and tested on + machines with version 2.0 and 2.0.21b; it should work with versions 2.x ; + however, vanilla versions 2.2.3 and 2.2.4 contain a bug which does not allow + to change online at the same time the user certificate and key files, and + therefore to use all the features implemented in ROOT for this kind of + authentication. An experimental patch is provided which however requires + access to the GTK source. + + +2) Compiling ROOT with Globus support + + To compile ROOT with Globus support run the 'configure' script with the flag + '--enable-globus'; the script expects the variable GLOBUS_LOCATION to be + defined and pointing to the location with the 'bin', 'lib' and 'include' + dirs for the GTK . It is definitely better to have this variable defined + correctly (especially on the client side); however, for compilation purposes + it is possible to force a specific directory for the GTK running configure + with + + --with-globus-dir=<GTK_path> + + The experimental patch mentioned above can be activated with the flag + + --with-globus-patch-dir=<GTK_source> + + where <GTK_source> points to the path containing the source of the GTK . + + While running configure you should get the following printed + + ... +Checking for openssl/x509.h ... <Your_GLOBUS_LOCATION>/include/<flavour> +Checking for openssl/pem.h ... <Your_GLOBUS_LOCATION>/include/<flavour> +Checking for globus_gss_assist.h ... <Your_GLOBUS_LOCATION>/include/<flavour> +Checking for libglobus_gss_assist_<flavour> ... <Your_GLOBUS_LOCATION>/lib +Checking for libglobus_gssapi_gsi_<flavour> ... <Your_GLOBUS_LOCATION>/lib +Checking for libssl_<flavour> ... <Your_GLOBUS_LOCATION>/lib +Checking for libcrypto_<flavour> ... <Your_GLOBUS_LOCATION>/lib +Checking for globus-user-env.sh ... <Your_GLOBUS_LOCATION>/etc +Checking for grid-proxy-init ... <Your_GLOBUS_LOCATION>/bin +Applying experimental patch to globus_gsi_system_config.c + ... + where <flavour> is either gcc32 or gcc32dbg. The last message appears only + if you have activated the experimental patch mentioned above. + +3) Before running, after compilation/installation + + 3.1) On the CLIENT side + + Make sure that valid certificates are in the correct places and that + valid credentials can be initialized; this can be tested by running + + grid-proxy-init + + and entering the pass phrase; you may have to source the relevant shell + file to have this command recognized: + + source $GLOBUS_LOCATION/etc/globus-user-env.csh + or + source $GLOBUS_LOCATION/etc/globus-user-env.sh . + + If you are sure about you capabilities to get valid credentials, you + don't need to initialize them outside the root session, for ROOT checks + the credentials and prompts for the pass phrase if they are missing or + invalid. + + There are three files/dirs relevant for proxy initialization: + + a) user certificate file; default is $HOME/.globus/usercert.pem ; can + be changed by setting the variable "X509_USER_CERT" to the full + path + + b) user private key file; default is $HOME/.globus/userkey.pem ; can + be changed by setting the variable "X509_USER_KEY" to the full path + + c) directory with certificates of the known Certificate Authorities; + default is /etc/grid-security/certificates ; can be changed by + setting the variable "X509_CERT_DIR" to the full path. + + All this variables can be changed by the user before running root or + during a root session. Globus authentication can be requested by: + + 1) Setting + + Rootd.Authentication 3 + Proofd.Authentication 3 + + in the $HOME/.rootrc file; other parameters can be changed at this + level: + + - the proxy duration, in hours + + Globus.ProxyDuration : <hours> + + - the number of bits to be used for the key (should be a power of 2) + + Globus.ProxyKeyBits: 1024 + + - a Globus login defining the relevant files mentioned above: + + Globus.Login: cd:~/.globus cf:usercert.pem \ + kf:userkey.pem ad:certificates + + with the meaning of the different keys being: + + "cd" defines the directory with the user certificate and + private key; default: $HOME/.globus + "cf" user certificate file (in the dir specified by "cd"); + default: usercert.pem + "kf" user key file (in the dir specified by "cd"); + default: userkey.pem + "ad" directory with certificates of the known Certificate + Authorities; default: /etc/grid-security/certificates + + Both "cd" and "ad" can be given as absolute paths (starting + with '/'), relative to $HOME (starting with ~/) or relative to + $HOME/.globus (in the other cases). + + 2) Specifying an entry in .authrootrc (see README.AUTH for more details) + + This allows to be host and user specific and to initialize proxies + for two or more different users in the same session. + + 3) During a ROOT session by creating (or modifying) a THostAuth + instantiation (see README.AUTH for more details) + + Upon successful authentication the user is logged on remotely with the + user name specified in the gridmap file on the remote server; if there + is no entry is found in the gridmap corresponding to the client DN, an + attempt is made to guess it from the CN part of the DN. + + + 3.2) On the SERVER side + + The servers rootd/proofd make use of the host certificate ( <CA bla + bla>/CN=host/<FQDN>) located by default in + + /etc/grid-security/hostcert.pem + + and the related private key (default in + /etc/grid-security/hostkey.pem). The environment variable + X509_USER_CERT should be set to point to this file. + + No proxies are needed for the host certificate. + + Server Configuration file: + both daemon servers accept as argument + + -C <server_globus_conf_file> + + By default this file is looked for in /etc/root/hostcert.conf or in + $ROOTSYS/etc/hostcert.conf and it contains record lines specifying + + <certificates_dir> <host_cert_file> <host_cert_key> <grid_mapfile> + + Record lines starting with '#' are considered as comments; an example: + + < bof > + # This is an example of hostcert.conf ... + /etc/grid-security/certificates /etc/grid-security/hostcert.pem /etc/grid-security/hostkey.pem /etc/grid-security/grid-mapfile + < eof > + + There may be as many line as there are valid certificate settings + (corresponding to different Certificates Authorities and potentially + to different DN-to-UserName mappings ). When a request for globus + authentication arrives, rootd/proofd look among their own certificates + if there is one issued by the same CA which has issued the client + certificate; if the search is successful they communicate the related + subject name to the client and setenv the relevant variables using to + the chosen configuration set. + +4) Trying out + + Trying to access a remote file should give this on the client side (assuming + globus credentials have not been initialized before): + +root [1] TFile *f1 = TFile::Open("root://<remote_FQDN>/test.root","read") +Your identity: /O=Grid/OU=GlobusTest/OU=simpleCA-arthux.cern.ch/OU=cern.ch/CN=qwerty +Enter GRID pass phrase for this identity: +Creating proxy ....................... Done +Your proxy is valid until Wed May 28 02:46:12 2003 +root [2] + + In the /var/log/messages on the server you should get something like ( with -d 3 in 'rootd') + +May 27 12:49:46 pcepsft43 rootd[24031]: RootdLoop: kind:2033 -- buf:'11820 -1 2 4 None' (len:17) -- Auth:0 +May 27 12:49:46 pcepsft43 rootd[24031]: RpdDefaultAuthAllow: default list of secure methods available: 4 1 2 3 +May 27 12:49:46 pcepsft43 rootd[24031]: RpdGlobusAuth: user: /O=Grid/OU=GlobusTest/OU=simpleCA-arthux.cern.ch/OU=cern.ch/CN=qwerty authenticated +May 27 12:49:46 pcepsft43 rootd[24031]: RpdGlobusAuth: logging as qwerty +May 27 12:49:46 pcepsft43 rootd[24031]: RootdLogin: user qwerty authenticated (OffSet: -1) +May 27 12:49:46 pcepsft43 rootd[24031]: RootdLoop: kind:2004 -- buf:'/test.root read' (len:10) -- Auth:1 + + The first authentication to a (remotehost,username) entity may be perceived + as slow; this is because a lot of exchanges are need to establish the + security context; however, the security context is kept until is valid, so + subsequent access to the same entity will be much faster (if this is not + so, make sure that you do not have set the 'reuse' flag to '0' or 'no'; see + README.AUTH). + + In a PROOF cluster, if the master requires Globus credentials for + authentication to slaves, these are automatically transmitted using a + shared memory. + +5) If it does not work ... + + Some tips: + + .1) make sure that local and remote times are synchronized within 5 minutes + .2) if GlobusAuthenticate is not found and you using /etc/ld.so.conf for + shared libraries you may need to run /sbin/ldconfig -v after compilation. + .3) Check location of certificate and private key files and certificate + directories; make sure they can be read by the root process + .4) Make sure that remote node accepts Globus authentication from your + local host + .5) Recompile with --with-globus-deb and check for more hints in the + flow of messages ... + .6) mailto: gerardo.ganis@cern.ch. + +-------------------------------------------------------------------------------------- +Last update: May 27, 2003 + diff --git a/clib/inc/rsaaux.h b/clib/inc/rsaaux.h new file mode 100644 index 0000000000000000000000000000000000000000..0b5191cc08717b02f4c2e120e0331d4007d7d648 --- /dev/null +++ b/clib/inc/rsaaux.h @@ -0,0 +1,87 @@ +/* @(#)root/clib:$Name: $:$Id: mmalloc.c,v 1.1.1.1 2000/05/16 17:00:43 rdm Exp $ */ +/* Author: */ + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* Header used by internal rsa funtions * +* * +*******************************************************************************/ +#ifndef _RSAAUX_H +#define _RSAAUX_H + +#ifndef _RSADEF_H +#include "rsadef.h" +#endif + +extern rsa_NUMBER a_one,a_two; + +/* + * Prototypes + */ + +void a_add P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void a_assign P(( rsa_NUMBER*, rsa_NUMBER* )); +int a_cmp P(( rsa_NUMBER*, rsa_NUMBER* )); +void a_div P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void a_div2 P(( rsa_NUMBER* )); +void a_ggt P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void a_imult P(( rsa_NUMBER*, rsa_INT, rsa_NUMBER* )); +void a_mult P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void a_sub P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void m_init P(( rsa_NUMBER*, rsa_NUMBER* )); +void m_add P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void m_mult P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +void m_exp P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +int n_bits P(( rsa_NUMBER*, int)); +void n_div P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); +int n_cmp P(( rsa_INT*, rsa_INT*, int )); +int n_mult P(( rsa_INT*, rsa_INT, rsa_INT*, int )); +int n_sub P(( rsa_INT*, rsa_INT*, rsa_INT*, int, int )); +int n_bitlen P(( rsa_NUMBER* )); + + + +/****************** + * prim.h * + ******************/ + +int p_prim P(( rsa_NUMBER*, int )); +void inv P(( rsa_NUMBER*, rsa_NUMBER*, rsa_NUMBER* )); + + +/****************** + * rnd.h * + ******************/ + +void gen_number P(( int, rsa_NUMBER* )); +void init_rnd P(( void )); + + +/****************** + * aux.h * + ******************/ + +void do_crypt(char *, char *, int, rsa_NUMBER *); + +/* +int get_clear(char *, FILE *); +int get_enc(char *, FILE *); +int put_clear(char *, FILE *); +int put_enc(char *, FILE *); +*/ + +#endif diff --git a/clib/inc/rsadef.h b/clib/inc/rsadef.h new file mode 100644 index 0000000000000000000000000000000000000000..d6d87ca1a958cdaafd992bb4725f4bfbc77e814b --- /dev/null +++ b/clib/inc/rsadef.h @@ -0,0 +1,122 @@ +/* @(#)root/clib:$Name: $:$Id: mmalloc.c,v 1.1.1.1 2000/05/16 17:00:43 rdm Exp $ */ +/* Author: */ + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* General rsa definitions header * +* * +*******************************************************************************/ + +#ifndef _RSADEF_H +#define _RSADEF_H + +typedef unsigned short rsa_INT; /* muss MAXINT fassen */ +typedef unsigned long rsa_LONG; /* muss (MAXINT+1)^2 -1 fassen */ + +#ifndef P +#if defined (__STDC__) || defined (__cplusplus) +#define P(x) x +#else +#define P(x) () +#endif +#endif + +/* + * (MAXINT+1)-adic Zahlen + */ + +/* + * MAXINT Maximale Zahl pro Elemenmt (muss int sein) + * MAXBIT Maximales Bit von MAXINT + * LOWBITS Anzahl der consekutiven low Bits von MAXINT + * HIGHBIT Hoechsten Bit von MAXINT + * TOINT muss (INT)( (x) % MAXINT) ergeben + * MAXLEN Laenge der INT Array in jeder NUMBER + */ + +#define rsa_MAXINT 0xFFFF + +#if rsa_MAXINT == 99 +#define rsa_MAXBIT 7 +#define rsa_LOWBITS 2 +#endif +#if rsa_MAXINT == 9 +#define rsa_MAXBIT 4 +#define rsa_LOWBITS 1 +#endif +#if rsa_MAXINT == 1 +#define rsa_MAXBIT 1 +#endif +#if rsa_MAXINT == 0xFF +#define rsa_MAXBIT 8 +#define rsa_TOINT(x) ((rsa_INT)(x)) /* ACHTUNG !!!!! */ +#endif +#if rsa_MAXINT == 0xFFFF +#define rsa_MAXBIT 16 +#define rsa_TOINT(x) ((rsa_INT)(x)) /* ACHTUNG !!!!! */ +#endif + +#ifndef rsa_MAXBIT +#include "<< ERROR: rsa_MAXBIT must be defined >>" +#endif +#ifndef rsa_LOWBITS +#if rsa_MAXINT == (1 << rsa_MAXBIT) - 1 +#define rsa_LOWBITS rsa_MAXBIT +#else +#include "<< ERROR: rsa_LOWBITS must be defined >>" +#endif +#endif + +#define rsa_MAXLEN (300*8/(rsa_MAXBIT + 1)) +#define rsa_STRLEN (rsa_MAXLEN*rsa_MAXBIT/4) +#define rsa_HIGHBIT (1 << (rsa_MAXBIT-1) ) + +#if rsa_LOWBITS == rsa_MAXBIT +#define rsa_DIVMAX1(x) ((x) >> rsa_MAXBIT) +#define rsa_MODMAX1(x) ((x) & rsa_MAXINT) +#define rsa_MULMAX1(x) ((x) << rsa_MAXBIT) +#else +#define rsa_DIVMAX1(x) ((x) / (rsa_MAXINT+1)) +#define rsa_MODMAX1(x) ((x) % (rsa_MAXINT+1)) +#define rsa_MULMAX1(x) ((x) * (unsigned)(rsa_MAXINT+1)) +#endif + +#ifndef rsa_TOINT +#define rsa_TOINT(x) ((rsa_INT)rsa_MODMAX1(x)) +#endif + +typedef struct { + int n_len; /* Hoechster benutzter Index */ + rsa_INT n_part[rsa_MAXLEN]; +} rsa_NUMBER; + +#define rsa_NUM0P ((rsa_NUMBER *)0) /* Abkuerzung */ + +// Key structures +typedef struct { + rsa_NUMBER n; // modulus + rsa_NUMBER e; // private or public exponent +} rsa_KEY; +typedef struct { + int len; // length of 'data' in bytes + char *keys; // 'HEX[n]#HEX[d]\0' +} rsa_KEY_export; + + +#endif + + diff --git a/clib/inc/rsafun.h b/clib/inc/rsafun.h new file mode 100644 index 0000000000000000000000000000000000000000..13ffb073196954947f4e72dbc1bc9237b7edacf4 --- /dev/null +++ b/clib/inc/rsafun.h @@ -0,0 +1,66 @@ +// @(#)root/clib:$Name: $:$Id: TSocket.cxx,v 1.10 2002/05/18 08:22:00 brun Exp $ +// Author: + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* Hooks for useful rsa funtions * +** * +*******************************************************************************/ + +#include <stdio.h> + +#ifndef ROOT_rsafun +#define ROOT_rsafun + +extern "C" { +#ifndef _RSADEF_H +#include "rsadef.h" +#endif +} + + +typedef rsa_NUMBER (*rsa_genprim_t)(int, int); +typedef int (*rsa_genrsa_t)(rsa_NUMBER, rsa_NUMBER, rsa_NUMBER *, rsa_NUMBER *, rsa_NUMBER *); +typedef int (*rsa_encode_t)(char *, int, rsa_NUMBER, rsa_NUMBER); +typedef int (*rsa_decode_t)(char *, int, rsa_NUMBER, rsa_NUMBER); +typedef int (*rsa_num_sput_t)(rsa_NUMBER*, char*, int ); +typedef int (*rsa_num_fput_t)(rsa_NUMBER*, FILE* ); +typedef int (*rsa_num_sget_t)(rsa_NUMBER*, char* ); +typedef int (*rsa_num_fget_t)(rsa_NUMBER*, FILE* ); +typedef int (*rsa_assign_t)(rsa_NUMBER *, rsa_NUMBER *); +typedef int (*rsa_cmp_t)(rsa_NUMBER *, rsa_NUMBER *); + + +class rsa_fun { + +public: + static rsa_genprim_t fg_rsa_genprim; + static rsa_genrsa_t fg_rsa_genrsa; + static rsa_encode_t fg_rsa_encode; + static rsa_decode_t fg_rsa_decode; + static rsa_num_sput_t fg_rsa_num_sput; + static rsa_num_fput_t fg_rsa_num_fput; + static rsa_num_sget_t fg_rsa_num_sget; + static rsa_num_fget_t fg_rsa_num_fget; + static rsa_assign_t fg_rsa_assign; + static rsa_cmp_t fg_rsa_cmp; + + rsa_fun(rsa_genprim_t, rsa_genrsa_t, rsa_encode_t, rsa_decode_t, + rsa_num_sput_t, rsa_num_fput_t, rsa_num_sget_t, rsa_num_fget_t, rsa_assign_t, rsa_cmp_t); +}; + +#endif diff --git a/clib/inc/rsalib.h b/clib/inc/rsalib.h new file mode 100644 index 0000000000000000000000000000000000000000..12a19e6ba039aa8344d78532f81385aec51dcca0 --- /dev/null +++ b/clib/inc/rsalib.h @@ -0,0 +1,44 @@ +/* @(#)root/clib:$Name: $:$Id: mmalloc.c,v 1.1.1.1 2000/05/16 17:00:43 rdm Exp $ */ +/* Author: */ + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* prototypes for rsa funtions of public interest * +* * +*******************************************************************************/ + +#ifndef _RSALIB_H +#define _RSALIB_H + +rsa_NUMBER rsa_genprim(int, int); +int rsa_genrsa(rsa_NUMBER, rsa_NUMBER, rsa_NUMBER *, rsa_NUMBER *, rsa_NUMBER *); +int rsa_encode(char *, int, rsa_NUMBER, rsa_NUMBER); +int rsa_decode(char *, int, rsa_NUMBER, rsa_NUMBER); + + +/****************** + * nio.h * + ******************/ + +int rsa_num_sput( rsa_NUMBER*, char*, int ); +int rsa_num_fput( rsa_NUMBER*, FILE* ); +int rsa_num_sget( rsa_NUMBER*, char* ); +int rsa_num_fget( rsa_NUMBER*, FILE* ); + +#endif + + diff --git a/clib/src/rsaaux.c b/clib/src/rsaaux.c new file mode 100644 index 0000000000000000000000000000000000000000..98de437a20b3fcd0497ed5c1f6d53cde0ed697f0 --- /dev/null +++ b/clib/src/rsaaux.c @@ -0,0 +1,1121 @@ +/* @(#)root/clib:$Name: $:$Id: mmalloc.c,v 1.1.1.1 2000/05/16 17:00:43 rdm Exp $ */ +/* Author: */ + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* Internal rsa funtions * +* * +*******************************************************************************/ +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + +#include "rsaaux.h" +#include "rsalib.h" + +/******************************************************************************* +* * +* arith.c * +* * +********************************************************************************/ + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!! ACHTUNG !!!!!!!!!!!!!!!!!!!!!!!!!!!! + * Es findet keinerlei Ueberpruefung auf Bereichsueberschreitung + * statt. Alle Werte muessen natuerliche Zahlen aus dem Bereich + * 0 ... (rsa_MAXINT+1)^rsa_MAXLEN-1 sein. + * + * + * Bei keiner Funktion oder Hilsfunktion werden Annahmen getroffen, + * ueber die Verschiedenheit von Eingabe- & Ausgabe-Werten. + * + * + * Funktionen: + * + * a_add( s1, s2, d ) + * rsa_NUMBER *s1,*s2,*d; + * *d = *s1 + *s2; + * + * a_assign( *d, *s ) + * rsa_NUMBER *d,*s; + * *d = *s; + * + * int a_cmp( c1, c2 ) + * rsa_NUMBER *c1,*c2; + * 1 : falls *c1 > *c2 + * 0 : falls *c1 == *c2 + * -1 : falls *c1 < *c2 + * + * a_div( d1, d2, q, r ) + * rsa_NUMBER *d1,*d2,*q,*r; + * *q = *d1 / *d2 Rest *r; + * + * a_div2( n ) + * rsa_NUMBER *n; + * *n /= 2; + * + * a_ggt( a, b, f ) + * rsa_NUMBER *a,*b,*f; + * *f = ( *a, *b ); + * + * a_imult( n, m, d ) + * rsa_NUMBER *n; + * rsa_INT m; + * rsa_NUMBER *d; + * *d = *n * m + * + * a_mult( m1, m2, d ) + * rsa_NUMBER *m1,*m2,*d; + * *d = *m1 * *m2; + * + * a_sub( s1, s2, d ) + * rsa_NUMBER *s1,*s2,*d; + * *d = *s1 - *s2; + * + * Modulare Funktionen + * m_init( n, o ) + * rsa_NUMBER *n,*o; + * Initialsierung der Modularen Funktionen + * o != 0 : *o = alter Wert + * + * m_add( s1, s2, d ) + * rsa_NUMBER *s1, *s2, *d; + * *d = *s1 + *s2; + * + * m_mult( m1, m2, d ) + * rsa_NUMBER *m1,*m2,*d; + * + * m_exp( x, n, z ) + * rsa_NUMBER *x,*n,*z; + * *z = *x exp *n; + * + * + * Hilfs-Funktionen: + * + * int n_bits( n, b ) + * rsa_NUMBER *n; + * int b; + * return( unterste b Bits der Dualdarstellung von n) + * + * n_div( d1, z2, q, r ) + * rsa_NUMBER *d1,z2[rsa_MAXBIT],*q,*r; + * *q = *d1 / z2[0] Rest *r; + * z2[i] = z2[0] * 2^i, i=0..rsa_MAXBIT-1 + * + * int n_cmp( i1, i2, l ) + * rsa_INT i1[l], i2[l]; + * 1 : falls i1 > i2 + * 0 : falls i1 == i2 + * -1 : falls i1 < i2 + * + * int n_mult( n, m, d, l) + * rsa_INT n[l], m, d[]; + * d = m * n; + * return( sizeof(d) ); d.h. 'l' oder 'l+1' + * + * int n_sub( p1, p2, p3, l, lo ) + * rsa_INT p1[l], p2[lo], p3[]; + * p3 = p1 - p2; + * return( sizeof(p3) ); d.h. '<= min(l,lo)' + * + * int n_bitlen( n ) + * rsa_NUMBER *n; + * return( sizeof(n) in bits ) + * + */ + + +/* + * Konstante 1, 2 + */ +rsa_NUMBER a_one = { + 1, + { (rsa_INT)1, }, +}; + +rsa_NUMBER a_two = { +#if rsa_MAXINT == 1 + 2, + { 0, (rsa_INT)1, }, +#else + 1, + { (rsa_INT)2, }, +#endif +}; + + +/* + * Vergleiche zwei rsa_INT arrays der Laenge l + */ +int n_cmp( i1, i2, l ) +rsa_INT *i1,*i2; +int l; +{ + i1 += (l-1); /* Pointer ans Ende */ + i2 += (l-1); + + for (;l--;) + if ( *i1-- != *i2-- ) + return( i1[1] > i2[1] ? 1 : -1 ); + + return(0); +} + +/* + * Vergleiche zwei rsa_NUMBER + */ +int a_cmp( c1, c2 ) +rsa_NUMBER *c1,*c2; +{ + int l; + /* bei verschiedener Laenge klar*/ + if ( (l=c1->n_len) != c2->n_len) + return( l - c2->n_len); + + /* vergleiche als arrays */ + return( n_cmp( c1->n_part, c2->n_part, l) ); +} + +/* + * Zuweisung einer rsa_NUMBER (d = s) + */ +void a_assign( d, s ) +rsa_NUMBER *d,*s; +{ + int l; + + if (s == d) /* nichts zu kopieren */ + return; + + if ((l=s->n_len)) + memcpy( d->n_part, s->n_part, sizeof(rsa_INT)*l); + + d->n_len = l; +} + +/* + * Addiere zwei rsa_NUMBER (d = s1 + s2) + */ +void a_add( s1, s2, d ) +rsa_NUMBER *s1,*s2,*d; +{ + int l,lo,ld,same; + register rsa_LONG sum; + register rsa_INT *p1,*p2,*p3; + register rsa_INT b; + + /* setze s1 auch die groessere Zahl */ + l = s1->n_len; + if ( (l=s1->n_len) < s2->n_len) { + rsa_NUMBER *tmp = s1; + + s1 = s2; + s2 = tmp; + + l = s1->n_len; + } + + ld = l; + lo = s2->n_len; + p1 = s1->n_part; + p2 = s2->n_part; + p3 = d->n_part; + same = (s1 == d); + sum = 0; + + while (l --) { + if (lo) { /* es ist noch was von s2 da */ + lo--; + b = *p2++; + } + else + b = 0; /* ansonten 0 nehmen */ + + sum += (rsa_LONG)*p1++ + (rsa_LONG)b; + *p3++ = rsa_TOINT(sum); + + if (sum > (rsa_LONG)rsa_MAXINT) { /* carry merken */ + sum = 1; + } + else + sum = 0; + + if (!lo && same && !sum) /* nichts mehr zu tuen */ + break; + } + + if (sum) { /* letztes carry beruecksichtigen */ + ld++; + *p3 = sum; + } + + d->n_len = ld; /* Laenge setzen */ +} + +/* + * Subtrahiere zwei rsa_INT arrays. return( Laenge Ergebniss ) + * l == Laenge p1 + * lo== Laenge p3 + */ +int n_sub( p1, p2, p3, l, lo ) +rsa_INT *p1,*p2,*p3; +int l,lo; +{ + int ld,lc,same; + int over = 0; + register rsa_LONG dif; + rsa_LONG a,b; + + same = (p1 == p3); /* frueher Abbruch moeglich */ + + for (lc=1, ld=0; l--; lc++) { + a = (rsa_LONG)*p1++; + if (lo) { /* ist noch was von p2 da ? */ + lo--; + b = (rsa_LONG)*p2++; + } + else + b=0; /* ansonten 0 nehmen */ + + if (over) /* frueherer Overflow */ + b++; + if ( b > a) { /* jetzt Overflow ? */ + over = 1; + dif = (rsa_MAXINT +1) + a; + } + else { + over = 0; + dif = a; + } + dif -= b; + *p3++ = (rsa_INT)dif; + + if (dif) /* Teil != 0 : Laenge neu */ + ld = lc; + if (!lo && same && !over) { /* nichts mehr zu tuen */ + if (l > 0) /* Laenge korrigieren */ + ld = lc + l; + break; + } + } + + return( ld ); +} + +/* + * Subtrahiere zwei rsa_NUMBER (d= s1 - s2) + */ +void a_sub( s1, s2, d ) +rsa_NUMBER *s1,*s2,*d; +{ + d->n_len = n_sub( s1->n_part, s2->n_part, d->n_part + ,s1->n_len, s2->n_len ); +} + +/* + * Mulitipliziere rsa_INT array der Laenge l mit einer rsa_INT (d = n * m) + * return neue Laenge + */ +int n_mult( n, m, d, l) +register rsa_INT *n; +register rsa_INT m; +rsa_INT *d; +int l; +{ + int i; + register rsa_LONG mul; + + for (i=l,mul=0; i; i--) { + mul += (rsa_LONG)m * (rsa_LONG)*n++; + *d++ = rsa_TOINT(mul); + mul = rsa_DIVMAX1( mul ); + } + + if (mul) { /* carry ? */ + l++; + *d = mul; + } + + return( l ); +} + +/* + * Mulitipliziere eine rsa_NUMBER mit einer rsa_INT (d = n * m) + */ +void a_imult( n, m, d ) +rsa_NUMBER *n; +rsa_INT m; +rsa_NUMBER *d; +{ + if (m == 0) + d->n_len=0; + else if (m == 1) + a_assign( d, n ); + else + d->n_len = n_mult( n->n_part, m, d->n_part, n->n_len ); +} + +/* + * Multipliziere zwei rsa_NUMBER (d = m1 * m2) + */ +void a_mult( m1, m2, d ) +rsa_NUMBER *m1,*m2,*d; +{ + static rsa_INT id[ rsa_MAXLEN ]; /* Zwischenspeicher */ + register rsa_INT *vp; /* Pointer darin */ + register rsa_LONG sum; /* Summe fuer jede Stelle */ + register rsa_LONG tp1; /* Zwischenspeicher fuer m1 */ + register rsa_INT *p2; + rsa_INT *p1; + int l1,l2,ld,lc,l,i,j; + + l1 = m1->n_len; + l2 = m2->n_len; + l = l1 + l2; + if (l >= rsa_MAXLEN) + abort(); + + for (i=l, vp=id; i--;) + *vp++ = 0; + + /* ohne Uebertrag in Zwischenspeicher multiplizieren */ + for ( p1 = m1->n_part, i=0; i < l1 ; i++, p1++) { + + tp1 = (rsa_LONG)*p1; + vp = &id[i]; + sum = 0; + for ( p2 = m2->n_part, j = l2; j--;) { + sum += (rsa_LONG)*vp + (tp1 * (rsa_LONG)*p2++); + *vp++ = rsa_TOINT( sum ); + sum = rsa_DIVMAX1(sum); + } + *vp++ += (rsa_INT)sum; + } + + /* jetzt alle Uebertraege beruecksichtigen */ + ld = 0; + for (lc=0, vp=id, p1=d->n_part; lc++ < l;) { + if ( (*p1++ = *vp++)) + ld = lc; + } + + d->n_len = ld; +} + + +/* + * Dividiere Zwei rsa_NUMBER mit Rest (q= d1 / z2[0] Rest r) + * z2[i] = z2[0] * 2^i, i=0..rsa_MAXBIT-1 + * r = 0 : kein Rest + * q = 0 : kein Quotient + */ +void n_div( d1, z2, q, r ) +rsa_NUMBER *d1,*z2,*q,*r; +{ + static rsa_NUMBER dummy_rest; /* Dummy Variable, falls r = 0 */ + static rsa_NUMBER dummy_quot; /* Dummy Variable, falla q = 0 */ + rsa_INT *i1,*i1e,*i3; + int l2,ld,l,lq; +#if rsa_MAXINT != 1 + rsa_INT z; + int pw,l2t; +#endif + + if (!z2->n_len) + abort(); + + if (!r) + r = &dummy_rest; + if (!q) + q = &dummy_quot; + + a_assign( r, d1 ); /* Kopie von d1 in den Rest */ + + l2= z2->n_len; /* Laenge von z2[0] */ + l = r->n_len - l2; /* Laenge des noch ''rechts'' liegenden + Stuecks von d1 */ + lq= l +1; /* Laenge des Quotienten */ + i3= q->n_part + l; + i1= r->n_part + l; + ld = l2; /* aktuelle Laenge des ''Vergleichsstuecks'' + von d1 */ + i1e= i1 + (ld-1); + + for (; l >= 0; ld++, i1--, i1e--, l--, i3--) { + *i3 = 0; + + if (ld == l2 && ! *i1e) { + ld--; + continue; + } + + if ( ld > l2 || (ld == l2 && n_cmp( i1, z2->n_part, l2) >= 0) ) { +#if rsa_MAXINT != 1 + /* nach 2er-Potenzen zerlegen */ + for (pw=rsa_MAXBIT-1, z=(rsa_INT)rsa_HIGHBIT; pw >= 0; pw--, z /= 2) { + if ( ld > (l2t= z2[pw].n_len) + || (ld == l2t + && n_cmp( i1, z2[pw].n_part, ld) >= 0)) { + ld = n_sub( i1, z2[pw].n_part, i1, ld, l2t ); + (*i3) += z; + } + } +#else + /* bei rsa_MAXINT == 1 alles viel einfacher */ + ld = n_sub( i1, z2->n_part, i1, ld, l2 ); + (*i3) ++; +#endif + } + } + + /* Korrektur, falls l von Anfang an Negativ war */ + l ++; + lq -= l; + ld += l; + + if (lq>0 && !q->n_part[lq -1]) /* evtl. Laenge korrigieren */ + lq--; + + q->n_len = lq; + r->n_len = ld -1; +} + +/* + * Dividiere Zwei rsa_NUMBER mit Rest (q= d1 / z2[0] Rest r) + * z2[i] = z2[0] * 2^i, i=0..rsa_MAXBIT-1 + * r = 0 : kein Rest + * q = 0 : kein Quotient + */ +void a_div( d1, d2, q, r ) +rsa_NUMBER *d1,*d2,*q,*r; +{ +#if rsa_MAXINT != 1 + rsa_NUMBER z2[rsa_MAXBIT]; + rsa_INT z; + int i; + + a_assign( &z2[0], d2 ); + for (i=1,z=2; i < rsa_MAXBIT; i++, z *= 2) + a_imult( d2, z, &z2[i] ); + + d2 = z2; +#endif + + n_div( d1, d2, q, r ); +} + +/* + * Dividiere eine rsa_NUMBER durch 2 + */ +void a_div2( n ) +rsa_NUMBER *n; +{ +#if rsa_MAXBIT == rsa_LOWBITS + register rsa_INT *p; + int i; + +#if rsa_MAXINT != 1 + register rsa_INT h; + register int c; + + c=0; + i= n->n_len; + p= &n->n_part[i-1]; + + for (; i--;) { + if (c) { + c = (h= *p) & 1; + h /= 2; + h |= rsa_HIGHBIT; + } + else { + c = (h= *p) & 1; + h /= 2; + } + + *p-- = h; + } + + if ( (i= n->n_len) && n->n_part[i-1] == 0 ) + n->n_len = i-1; + +#else /* rsa_MAXBIT != 1 */ + p = n->n_part; + i = n->n_len; + + if (i) { + n->n_len = i-1; + for (; --i ; p++) + p[0] = p[1]; + } +#endif /* rsa_MAXBIT != 1 */ +#else /* rsa_MAXBIT == rsa_LOWBITS */ + a_div( n, &a_two, n, rsa_NUM0P ); +#endif /* rsa_MAXBIT == rsa_LOWBITS */ +} + + +/* + * MODULO-FUNKTIONEN + */ + +static rsa_NUMBER mod_z2[ rsa_MAXBIT ]; + +/* + * Init + */ +void m_init( n, o ) +rsa_NUMBER *n,*o; +{ + rsa_INT z; + int i; + + if (o) + a_assign( o, &mod_z2[0] ); + + if (! a_cmp( n, &mod_z2[0]) ) + return; + + for (i=0,z=1; i < rsa_MAXBIT; i++, z *= 2) + a_imult( n, z, &mod_z2[i] ); +} + +void m_add( s1, s2, d ) +rsa_NUMBER *s1, *s2, *d; +{ + a_add( s1, s2, d ); + if (a_cmp( d, mod_z2) >= 0) + a_sub( d, mod_z2, d ); +} + +void m_mult( m1, m2, d ) +rsa_NUMBER *m1,*m2,*d; +{ + a_mult( m1, m2, d ); + n_div( d, mod_z2, rsa_NUM0P, d ); +} + +/* + * Restklassen Exponent + */ +void m_exp( x, n, z ) +rsa_NUMBER *x,*n,*z; +{ + rsa_NUMBER xt,nt; + + a_assign( &nt, n ); + a_assign( &xt, x ); + a_assign( z, &a_one ); + + while (nt.n_len) { + while ( ! (nt.n_part[0] & 1)) { + m_mult( &xt, &xt, &xt ); + a_div2( &nt ); + } + m_mult( &xt, z, z ); + a_sub( &nt, &a_one, &nt ); + } +} + +/* + * GGT + */ +void a_ggt( a, b, f ) +rsa_NUMBER *a,*b,*f; +{ + rsa_NUMBER t[2]; + int at,bt, tmp; + + a_assign( &t[0], a ); at= 0; + a_assign( &t[1], b ); bt= 1; + + if ( a_cmp( &t[at], &t[bt]) < 0) { + tmp= at; at= bt; bt= tmp; + } + /* euklidischer Algorithmus */ + while ( t[bt].n_len) { + a_div( &t[at], &t[bt], rsa_NUM0P, &t[at] ); + tmp= at; at= bt; bt= tmp; + } + + a_assign( f, &t[at] ); +} + +/* + * die untersten b bits der Dualdarstellung von n + * die bits muessen in ein int passen + */ +int n_bits(n,b) +rsa_NUMBER *n; +int b; +{ + rsa_INT *p; + int l; + unsigned r; + int m = (1<<b) -1; + + if ( n->n_len == 0) + return(0); + + if (rsa_LOWBITS >= b) + return( n->n_part[0] & m ); + +#if rsa_LOWBITS != 0 + l = (b-1) / rsa_LOWBITS; +#else + l = n->n_len -1; +#endif + for (p= &n->n_part[l],r=0; l-- >= 0 && b > 0; b-= rsa_LOWBITS, p--) { + r = rsa_MULMAX1( r ); + r += (unsigned)*p; + } + + return( r & m ); +} + +/* + * Anzahl der bits von n bei Dualdarstellung + */ +int n_bitlen( n ) +rsa_NUMBER *n; +{ + rsa_NUMBER b; + int i; + + a_assign( &b, &a_one ); + + for (i=0; a_cmp( &b, n) <= 0; a_mult( &b, &a_two, &b ), i++) + ; + + return(i); +} + + +/******************************************************************************* +* * +* prim.c * +* * +********************************************************************************/ + +/* + * RSA + * + * p,q prim + * p != q + * n = p*q + * phi = (p -1)*(q -1) + * e,d aus 0...n-1 + * e*d == 1 mod phi + * + * m aus 0...n-1 sei eine Nachricht + * + * Verschluesseln: + * E(x) = x^e mod n ( n,e oeffendlich ) + * + * Entschluesseln: + * D(x) = x^d mod n ( d geheim ) + * + * + * Sicherheit: + * + * p,q sollten bei mind. 10^100 liegen. + * (d,phi) == 1, das gilt fuer alle Primzahlen > max(p,q). + * Allerdings sollte d moeglichst gross sein ( d < phi-1 ) + * um direktes Suchen zu verhindern. + */ + + +/* + * FUNKTIONEN um RSA Schluessel zu generieren. + * + * int p_prim( n, m ) + * rsa_NUMBER *n; + * int m; + * 0 : n ist nicht prim + * 1 : n ist mit Wahrscheinlichkeit (1-1/2^m) prim + * ACHTUNG !!!! + * p_prim benutzt m_init + * + * inv( d, phi, e ) + * rsa_NUMBER *d,*phi,*e; + * *e = *d^-1 (mod phi) + * ACHTUNG !!!! + * p_prim benutzt m_init + */ + +/* + * Prototypes + */ +static int jak_f( rsa_NUMBER* ); +static int jak_g( rsa_NUMBER*, rsa_NUMBER* ); +static int jakobi( rsa_NUMBER*, rsa_NUMBER* ); + +/* + * Hilfs-Funktion fuer jakobi + */ +static int jak_f( n ) +rsa_NUMBER *n; +{ + int f,ret; + + f = n_bits( n, 3 ); + + ret = ((f == 1) || (f == 7)) ? 1 : -1; + + return(ret); +} + +/* + * Hilfs-Funktuion fuer jakobi + */ +static int jak_g( a, n ) +rsa_NUMBER *a,*n; +{ + int ret; + + if ( n_bits( n, 2) == 1 || + n_bits( a, 2) == 1 ) + ret = 1; + else + ret = -1; + + return(ret); +} + +/* + * Jakobi-Symbol + */ +static int jakobi( a, n ) +rsa_NUMBER *a,*n; +{ + rsa_NUMBER t[2]; + int at,nt, ret; + + a_assign( &t[0], a ); at = 0; + a_assign( &t[1], n ); nt = 1; + + /* + * b > 1 + * + * J( a, b) = + * a == 1 : 1 + * a == 2 : f(n) + * a == 2*b : J(b,n)*J(2,n) ( == J(b,n)*f(n) ) + * a == 2*b -1 : J(n % a,a)*g(a,n) + * + */ + + ret = 1; + while (1) { + if (! a_cmp(&t[at],&a_one)) { + break; + } + if (! a_cmp(&t[at],&a_two)) { + ret *= jak_f( &t[nt] ); + break; + } + if ( ! t[at].n_len ) /* Fehler :-) */ + abort(); + if ( t[at].n_part[0] & 1) { /* a == 2*b -1 */ + int tmp; + + ret *= jak_g( &t[at], &t[nt] ); + a_div( &t[nt], &t[at], rsa_NUM0P, &t[nt] ); + tmp = at; at = nt; nt = tmp; + } + else { /* a == 2*b */ + ret *= jak_f( &t[nt] ); + a_div2( &t[at] ); + } + + } + + return(ret); +} + +/* + * Probabilistischer Primzahltest + * + * 0 -> n nicht prim + * 1 -> n prim mit (1-1/2^m) Wahrscheinlichkeit. + * + * ACHTUNG !!!!!! + * p_prim benutzt m_init !! + * + */ +int p_prim( n, m ) +rsa_NUMBER *n; +int m; +{ + rsa_NUMBER gt,n1,n2,a; + rsa_INT *p; + int i,w,j; + + if (a_cmp(n,&a_two) <= 0 || m <= 0) + abort(); + + a_sub( n, &a_one, &n1 ); /* n1 = -1 mod n */ + a_assign( &n2, &n1 ); + a_div2( &n2 ); /* n2 = ( n -1) / 2 */ + + m_init( n, rsa_NUM0P ); + + w = 1; + for (; w && m; m--) { + /* ziehe zufaellig a aus 2..n-1 */ + do { + for (i=n->n_len-1, p=a.n_part; i; i--) + *p++ = (rsa_INT)rand(); + if ((i=n->n_len) ) + *p = (rsa_INT)( rand() % ((unsigned long)n->n_part[i-1] +1) ); + while ( i && ! *p ) + p--,i--; + a.n_len = i; + } while ( a_cmp( &a, n) >= 0 || a_cmp( &a, &a_two) < 0 ); + + /* jetzt ist a fertig */ + + /* + * n ist nicht prim wenn gilt: + * (a,n) != 1 + * oder + * a^( (n-1)/2) != J(a,n) mod n + * + */ + + a_ggt( &a, n, > ); + if ( a_cmp( >, &a_one) == 0) { + + j= jakobi( &a, n ); + m_exp( &a, &n2, &a ); + + if ( ( a_cmp( &a, &a_one) == 0 && j == 1 ) + || ( a_cmp( &a, &n1 ) == 0 && j == -1) ) + w = 1; + else + w = 0; + } + else + w = 0; + } + + return( w ); +} + +/* + * Berechne mulitiplikatives Inverses zu d (mod phi) + * d relativ prim zu phi ( d < phi ) + * d.h. (d,phi) == 1 + * + * ACHTUNG !!!! + * inv benutzt m_init + */ +void inv( d, phi, e ) +rsa_NUMBER *d,*phi,*e; +{ + int k, i0, i1, i2; + rsa_NUMBER r[3],p[3],c; + + /* + * Berlekamp-Algorithmus + * ( fuer diesen Spezialfall vereinfacht ) + */ + + if (a_cmp(phi,d) <= 0) + abort(); + + m_init( phi, rsa_NUM0P ); + + p[1].n_len = 0; + a_assign( &p[2], &a_one ); + a_assign( &r[1], phi ); + a_assign( &r[2], d ); + + k = -1; + do { + k++; + i0=k%3; i1=(k+2)%3; i2=(k+1)%3; + a_div( &r[i2], &r[i1], &c, &r[i0] ); + m_mult( &c, &p[i1], &p[i0] ); + m_add( &p[i0], &p[i2], &p[i0] ); + } while (r[i0].n_len); + + if ( a_cmp( &r[i1], &a_one) ) /* r[i1] == (d,phi) muss 1 sein */ + abort(); + + if ( k & 1 ) /* falsches ''Vorzeichen'' */ + a_sub( phi, &p[i1], e ); + else + a_assign( e, &p[i1] ); +} + + +/******************************************************************************* +* * +* rnd.c * +* * +********************************************************************************/ + +void gen_number( len, n ) +rsa_NUMBER *n; +int len; +{ + char *hex = "0123456789ABCDEF" ; + char num[ rsa_MAXLEN*rsa_MAXBIT/4 +1 ]; + char *p; + int i,l; + + p=&num[ sizeof(num) -1]; + *p-- = '\0'; + + for (l=len; l--; p--) { + i = rand() % 16; + *p = hex[ i ]; + } + p++; + + while (len-- && *p == '0') + p++; + + rsa_num_sget( n, p ); +} + +void init_rnd() +{ + long time(); + unsigned int seed; + + seed = (unsigned int) time((long *)0); + (void)srand( seed ); +} + + +/******************************************************************************* +* * +* aux.c * +* * +********************************************************************************/ + +/* These are not needed, for the moment + +int get_clear( p, fp ) +char *p; +FILE *fp; +{ + int n; + + n = fread( p, 1, clear_siz, fp ); + + if (n <= 0) + return(0); + + memset( p + n, 0, enc_siz - n ); + + return(1); +} + +int get_enc( p, fp ) +char *p; +FILE *fp; +{ + int n; + + n = fread( p, 1, enc_siz, fp ); + + if (n != enc_siz) + return(0); + + return(1); +} + +int put_clear( p, fp ) +char *p; +FILE *fp; +{ + int n; + + n = fwrite( p, 1, clear_siz, fp ); + + if (n != clear_siz) + return(0); + + return(1); +} + +int put_enc( p, fp ) +char *p; +FILE *fp; +{ + int n; + + n = fwrite( p, 1, enc_siz, fp ); + + if (n != enc_siz) + return(0); + + return(1); +} + +*/ + +void do_crypt( s, d, len, e ) +char *s; +char *d; +rsa_NUMBER *e; +int len; +{ + static char hex[] = "0123456789ABCDEF"; + rsa_NUMBER n; + char buf[ rsa_STRLEN + 1 ]; + char *ph; + int i,c; + + ph = buf + rsa_STRLEN; + ph[1] = '\0'; + + for (i=len; i; i--) { + c = *s++; + *ph-- = hex[ (c >> 4) & 0xF ]; + *ph-- = hex[ c & 0xF ]; + } + ph++; + + rsa_num_sget( &n, ph ); + + m_exp( &n, e, &n ); + + rsa_num_sput( &n, buf, rsa_STRLEN +1 ); + + ph = buf + (i=strlen(buf)) -1; + + for (; len; len--) { + if (i-- > 0) { + c = (strchr( hex, *ph) - hex) << 4; + ph--; + } + else + c=0; + if (i-- > 0) { + c |= strchr( hex, *ph) - hex; + ph--; + } + + *d++ = c; + } +} + diff --git a/clib/src/rsafun.cxx b/clib/src/rsafun.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1003b1d6605a57b3fcdb3857b8d3a7769eb6c840 --- /dev/null +++ b/clib/src/rsafun.cxx @@ -0,0 +1,71 @@ +// @(#)root/clib:$Name: $:$Id: TSocket.cxx,v 1.10 2002/05/18 08:22:00 brun Exp $ +// Author: + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* Hooks for useful rsa funtions * +* * +*******************************************************************************/ + +#include "rsafun.h" + + +extern "C" { + rsa_NUMBER rsa_genprim(int, int); + int rsa_genrsa(rsa_NUMBER, rsa_NUMBER, rsa_NUMBER *, rsa_NUMBER *, rsa_NUMBER *); + int rsa_encode(char *, int, rsa_NUMBER, rsa_NUMBER); + int rsa_decode(char *, int, rsa_NUMBER, rsa_NUMBER); + int rsa_num_sput( rsa_NUMBER*, char*, int ); + int rsa_num_fput( rsa_NUMBER*, FILE* ); + int rsa_num_sget( rsa_NUMBER*, char* ); + int rsa_num_fget( rsa_NUMBER*, FILE* ); + int rsa_assign( rsa_NUMBER*, rsa_NUMBER* ); + int rsa_cmp( rsa_NUMBER*, rsa_NUMBER* ); +} + +rsa_genprim_t rsa_fun::fg_rsa_genprim; +rsa_genrsa_t rsa_fun::fg_rsa_genrsa; +rsa_encode_t rsa_fun::fg_rsa_encode; +rsa_decode_t rsa_fun::fg_rsa_decode; +rsa_num_sput_t rsa_fun::fg_rsa_num_sput; +rsa_num_fput_t rsa_fun::fg_rsa_num_fput; +rsa_num_sget_t rsa_fun::fg_rsa_num_sget; +rsa_num_fget_t rsa_fun::fg_rsa_num_fget; +rsa_assign_t rsa_fun::fg_rsa_assign; +rsa_cmp_t rsa_fun::fg_rsa_cmp; + +// Static instantiation to load hooks during dynamic load +static rsa_fun rsa_init(&rsa_genprim,&rsa_genrsa,&rsa_encode,&rsa_decode, + &rsa_num_sput,&rsa_num_fput,&rsa_num_sget,&rsa_num_fget,&rsa_assign,&rsa_cmp); + +rsa_fun::rsa_fun(rsa_genprim_t genprim, rsa_genrsa_t genrsa, rsa_encode_t encode, rsa_decode_t decode, + rsa_num_sput_t num_sput, rsa_num_fput_t num_fput, rsa_num_sget_t num_sget, rsa_num_fget_t num_fget, + rsa_assign_t assign, rsa_cmp_t cmp) +{ + // ctor + + fg_rsa_genprim = genprim; + fg_rsa_genrsa = genrsa; + fg_rsa_encode = encode; + fg_rsa_decode = decode; + fg_rsa_num_sput = num_sput; + fg_rsa_num_fput = num_fput; + fg_rsa_num_sget = num_sget; + fg_rsa_num_fget = num_fget; + fg_rsa_assign = assign; + fg_rsa_cmp = cmp; +} diff --git a/clib/src/rsalib.c b/clib/src/rsalib.c new file mode 100644 index 0000000000000000000000000000000000000000..6b1e0baff9762ab3715b8a3b853aac26538a0d9a --- /dev/null +++ b/clib/src/rsalib.c @@ -0,0 +1,482 @@ +/* @(#)root/clib:$Name: $:$Id: mmalloc.c,v 1.1.1.1 2000/05/16 17:00:43 rdm Exp $ */ +/* Author: */ + +/******************************************************************************* +* * +* Copyright (c) Martin Nicolay, 22. Nov. 1988 * +* * +* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten * +* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter * +* verwendet werden. * +* * +* martin@trillian.megalon.de * +* * +* ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa * +* * +* Simple RSA public key code. * +* Adaptation in library for ROOT by G. Ganis, July 2003 * +* (gerardo.ganis@cern.ch) * +* * +* rsa funtions of public interest * +* * +*******************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <errno.h> + +#include "rsaaux.h" +#include "rsalib.h" + +static int clear_siz; /* clear-text blocksize */ +static int enc_siz; /* encoded blocksize */ + /* clear_siz < enc_siz */ + +int gLog = 0; + +rsa_NUMBER rsa_genprim(int len, int prob) +{ + rsa_NUMBER a_three,a_four; + rsa_NUMBER prim; + int i; + + a_add( &a_one, &a_two, &a_three ); + a_add( &a_two, &a_two, &a_four ); + + init_rnd(); + + do { + gen_number( len, &prim ); + } while ( !prim.n_len ); + + a_mult( &prim, &a_two, &prim ); + a_mult( &prim, &a_three, &prim ); + a_add( &prim, &a_one, &prim ); + + for (i=1 ;; i++) { + + if (p_prim( &prim, prob )) + break; + if (i % 2) + a_add( &prim, &a_four, &prim ); + else + a_add( &prim, &a_two, &prim ); + } + + return prim; +} + +int rsa_genrsa(rsa_NUMBER p1, rsa_NUMBER p2, rsa_NUMBER *n, rsa_NUMBER *e, rsa_NUMBER *d) +{ + rsa_NUMBER phi, *max_p; + int len; + + if ( !a_cmp( &p1, &p2) ) return 1; + + if (a_cmp( &p1, &p2) > 0) + max_p = &p1; + else + max_p = &p2; + + + a_mult( &p1, &p2, n ); + a_sub( &p1, &a_one, &phi ); + a_sub( &p2, &a_one, e ); + a_mult( &phi, e, &phi ); + + len = n_bitlen( &phi ); + len = ( len + 3) / 4; + + a_assign( &p1, &phi ); + a_sub( &p1, &a_one, &p1 ); + + init_rnd(); + + do { + do { + gen_number( len, d ); + } while (a_cmp( d, max_p) <= 0 || a_cmp( d, &p1) >= 0); + + a_ggt( d, &phi, e ); + } while ( a_cmp( e, &a_one) ); + + inv( d, &phi, e ); + + return 0; +} + + +int rsa_encode(char *bufin, int lin, rsa_NUMBER n, rsa_NUMBER e) +{ + /* Encodes plain string in 'bufin' (output in 'bufin') + Returns length of encoded string + (key validity is not checked) */ + + char buf[ rsa_STRLEN*2 ]; + char bufout[ rsa_STRLEN*2 ]; + int i, j, lout; + char *pout; + + enc_siz = ( n_bitlen( &n) + 7) / 8; + clear_siz = enc_siz -1; + m_init( &n, rsa_NUM0P ); + + pout = bufout; + lout = 0; + for ( i = 0; i < lin; i += clear_siz) { + + memcpy(buf,bufin+i,clear_siz); + + j = ((lin-i) < clear_siz) ? lin-i : clear_siz; + memset(buf+j,0,(enc_siz-j)); + + do_crypt( buf, buf, enc_siz, &e ); + + memcpy(pout,buf,enc_siz); + + pout += enc_siz; + lout += enc_siz; + } + + memcpy(bufin,bufout,lout); + + return lout; + +} + +int rsa_decode(char *bufin, int lin, rsa_NUMBER n, rsa_NUMBER e) +{ + /* Decodes string in 'bufin' (output in 'bufin') + Returns length of plaintext string + (key validity is not checked) */ + + char buf[ rsa_STRLEN*2 ]; + char bufout[ rsa_STRLEN*2 ]; + int i, lout; + char *pout; + + enc_siz = ( n_bitlen( &n) + 7) / 8; + clear_siz = enc_siz -1; + m_init( &n, rsa_NUM0P ); + + pout = bufout; + lout = 0; + for ( i = 0; i < lin; i += enc_siz) { + + memcpy(buf,bufin+i,enc_siz); + + do_crypt( buf, buf, enc_siz, &e ); + + memcpy(pout,buf,clear_siz); + + pout += clear_siz; + lout += clear_siz; + } + + memcpy(bufin,bufout,lout); + + return lout; + +} + + +/******************************************************************************* +* * +* nio.c * +* * +********************************************************************************/ + + +/* + * rsa_NUMBER io + */ + +/* + * Funktionen + * + * int num_sput( n, s, l) + * rsa_NUMBER *n; + * char s[l]; + * schreibt *n als Hex-Zahl in s + * + * int num_fput( n, f ) + * rsa_NUMBER *n; + * FILE *f; + * schreibt *n als Hex-Zahl in File f + * + * int num_sget( n, s ) + * rsa_NUMBER *n; + * char *s; + * liest Hex-Zahl s in *n ein + * + * int num_fget( n, f ) + * rsa_NUMBER *n; + * FILE *f; + * liest eine Hex-Zahl von f in *n ein + * + */ + + +static char *HEX="0123456789ABCDEF"; +static char *hex="0123456789abcdef"; + +static rsa_NUMBER bits[9]; +static rsa_NUMBER int16[16]; + +static int init = 0; + +void num_init() +{ + int i; + + if (init) return; + + a_assign( &bits[0], &a_one ); + for ( i=1; i<9; i++) + a_add( &bits[i-1], &bits[i-1], &bits[i] ); + + a_assign( &int16[0], &a_one ); + for ( i=1; i<16; i++) + a_add( &int16[i-1], &a_one, &int16[i] ); + + init = 1; +} + + +int rsa_num_sput( n, s, l) +rsa_NUMBER *n; +char *s; +int l; +{ +#if rsa_MAXINT == ( (1 << rsa_MAXBIT) - 1 ) + rsa_INT *p; + int bi,ab,i; + long b; + int first = 1; + + bi = rsa_MAXBIT * n->n_len; + ab = 4 - (bi + 3) % 4 -1; + p = &n->n_part[n->n_len -1]; + + if ( (bi+3) / 4 >= l ) + return(EOF); + + b = 0; + while (bi) { + b <<= (rsa_MAXBIT); + b |= (unsigned long)*p--; + bi -= rsa_MAXBIT; + ab += rsa_MAXBIT; + while (ab >= 4) { + i = (b >> (ab - 4)); + b &= ( 1L << (ab - 4)) -1L; + ab -= 4; + + if (first && !i) + continue; + first = 0; + *s++ = HEX[ i ]; + } + } + if (b) + abort(); + *s = '\0'; + + return (0); +#else + rsa_NUMBER r,q; + int i,b,p,len,low,high; + char *np; + + if (! init) + num_init(); + + a_assign( &q, n); + len = l; + np = s + l; + + for (; q.n_len && len > 1; len --) { + a_div( &q, &bits[4], &q, &r ); + for (p=8, b=0, i=3; i >= 0; i--, p /= 2) { + if ( a_cmp( &r, &bits[i]) >= 0) { + a_sub( &r, &bits[i], &r ); + b += p; + } + } + *--np = HEX[ b ]; + } + if (q.n_len) + return(EOF); + + l -= len; + len = l; + for (; l--; ) + *s++ = *np++; + + *s = '\0'; + + return (0); +#endif +} + + +int rsa_num_fput( n, f ) +rsa_NUMBER *n; +FILE *f; +{ + int j; + char *np; + char n_print[ rsa_STRLEN + 1 ]; + + if ( rsa_num_sput( n, n_print, sizeof( n_print) ) == EOF ) + return(EOF); + + for (j=0, np=n_print; *np ; np++, j++) { + if (j==64) { + fputs("\n",f); + j = 0; + } + putc((int)*np,f); + } + + if (j) + putc('\n',f); + + return(0); +} + + +int rsa_num_sget( n, s ) +rsa_NUMBER *n; +char *s; +{ +#if rsa_MAXINT == ( (1 << rsa_MAXBIT) - 1 ) + rsa_INT *p; + char *hp; + int bi,ab,i; + long b; + int first = 1; + + bi = 4 * strlen(s); + ab = rsa_MAXBIT - (bi + rsa_MAXBIT -1) % rsa_MAXBIT -1; + i = (bi + rsa_MAXBIT-1) / rsa_MAXBIT; + p = &n->n_part[ i -1 ]; + n->n_len = i; + + if ( i > rsa_MAXLEN ) + return(EOF); + + b = 0; + while (bi > 0) { + if ( (hp = strchr( HEX, *s )) ) + i = hp - HEX; + else if ((hp = strchr( hex, *s )) ) + i = hp - hex; + else + return(EOF); + s++; + + b <<= 4; + b |= (unsigned long)i; + bi -= 4; + ab += 4; + while (ab >= rsa_MAXBIT) { + i = (b >> (ab - rsa_MAXBIT)); + b &= ( 1L << (ab - rsa_MAXBIT)) -1L; + ab -= rsa_MAXBIT; + if (first && !i) { + p--; + n->n_len--; + } + else { + first = 0; + *p-- = i; + } + } + } + if (b) + abort(); + *s = '\0'; + + return (0); +#else + char *p; + int i,c; + + if (! init) + num_init(); + + n->n_len = 0; + while ( (c = *s++ & 0xFF)) { + if ( p= strchr( HEX, c) ) + i = p - HEX; + else if ( p= strchr( hex, c) ) + i = p - hex; + else + return(EOF); + + a_mult( n, &bits[4], n ); + if (i) + a_add( n, &int16[i-1], n ); + } + + return(0); +#endif +} + +int rsa_num_fget( n, f ) +rsa_NUMBER *n; +FILE *f; +{ + int j,c; + char *np; + char n_print[ rsa_STRLEN + 1 ]; + + np = n_print; + j = sizeof(n_print); + while ( (c=getc(f)) != EOF && ( isxdigit(c) || isspace(c)) ) { + if (isspace(c)) + continue; + if (! --j) + return(EOF); + *np++ = (char)c; + } + *np = '\0'; + + if (c != EOF) + ungetc(c,f); + + if ( rsa_num_sget( n, n_print) == EOF ) + return( EOF ); + + return(0); +} + +int rsa_cmp( c1, c2 ) +rsa_NUMBER *c1,*c2; +{ + int l; + /* bei verschiedener Laenge klar*/ + if ( (l=c1->n_len) != c2->n_len) + return( l - c2->n_len); + + /* vergleiche als arrays */ + return( n_cmp( c1->n_part, c2->n_part, l) ); +} + +void rsa_assign( d, s ) +rsa_NUMBER *d,*s; +{ + int l; + + if (s == d) /* nichts zu kopieren */ + return; + + if ((l=s->n_len)) + memcpy( d->n_part, s->n_part, sizeof(rsa_INT)*l); + + d->n_len = l; +} + diff --git a/etc/example.rootauthrc b/etc/example.rootauthrc new file mode 100644 index 0000000000000000000000000000000000000000..fe7dccb84038f810e1bf2483e0251f006ad573df --- /dev/null +++ b/etc/example.rootauthrc @@ -0,0 +1,194 @@ +# +# Example of .rootauthrc +# +# (NB: ROOT assumes this file to be $HOME/.rootauthrc, this can be changed +# by setting the environment variable ROOTAUTHRC to the appropriate +# absolute file pathname) +# +# This file contains information about authentication methods available for +# authentication vis-a-vis of a given host. It allows to define host specific +# methods and defaults for the info (username, certificates, ...) to be used. +# The information specified here superseeds the one found in .rootrc. +# +# Format: +# - lines starting with '#' are comment lines. +# +# - lines of the form 'include <file>' allow to include other files +# of this kind which are expanded exactly at the point where the +# 'include' appears. +# +# - lines of the form: +# +# proofserv <host1>[:<user1>][:<method1>] \ +# <host2>[:<user2>][:<method2>] \ +# <host3>[:<user3>][:<method3>] ... +# +# are active only for PROOF sessions and specify the list of hosts +# for which the authentication info should be transmitted to the master +# of the PROOF cluster; these directives are useful, for example, in +# the case of data servers external to the PROOF cluster that you may +# want to access via a given 'user' and a given authentication 'method'; +# 'user' and 'method' are not mandatory; for each <host> (an user, method) +# specified with 'proofserv' all the information that can be collected +# from the rest of the .rootauthrc file is sent to the master. +# +# - remaining valid lines are of the form: +# +# <host> [user <username>] <key> <info> +# +# where <host> is the host(s) identifier (see below), <key> is an +# option key and <info> is the relevant info whose format depends +# on <key>; 'user' indicates the username to whom the information +# applies; if absent, the info applies to all users. +# +# <host>: +# - hosts can specified either with their FQDN (e.g. pcepsft43.cern.ch) +# or their IP address (e.g. 137.138.99.73). +# - if <host>=default the following i<key> <info> applies to all +# hosts, unless host-specific entries are found. +# - the '*' character can be used in the first field of the name to +# indicate a set of machines, e.g. pcepsft*.cern.ch applies to all +# 'pcepsft' machines in the domain 'cern.ch' +# (to indicate all 'lxplus' machines you should use 'lxplus*.cern.ch' +# because internally the generic lxplus machine has a real name of +# the form lxplusnnn.cern.ch). +# - a whole domain can be indicated by its name, with at least two non +# null fields, eg 'cern.ch' or '.cern.ch', '.ch' is not accepted. +# - subsets of the IP address can also be used to indicate a set of +# machines; however, it is mandatory to end the subset with a '.', +# e.g. '137.138.' is an alternative way to indicate the 'cern.ch' +# domain, but '137.138' is invalid because ambiguous. +# +# <key> <info>: +# - valid keys are 'list' and 'method'; +# - if <key>=list, <info> contains the list of codes or short names for +# methods that can/should be tried for authentication wrt to <host>, +# in order of preference. +# Available methods are: +# +# Method short name code +# +# UsrPwd usrpwd 0 +# SRP srp 1 +# Kerberos krb5 2 +# Globus globus 3 +# SSH ssh 4 +# UidGid uidgid 5 (insecure) +# +# Example of a valid 'list' line: +# +# default list 4 +# lxplus*.cern.ch list ssh 3 krb5 +# +# The first line defines as default method SSH, this is equivalent +# of setting: +# +# Rootd.Authentication 4 +# Proofd.Authentication 4 +# +# in the .rootc file. +# +# The second line adds Globus and Kerberos as available methods +# for authentication to the lxplus machines (in addition to SSH): +# SSH the preferred first, Kerberos the last option. +# +# Having a line 'list' for a host is non mandatory: methods can +# also be defined directly via 'method' lines (see below); in +# such a case the first 'method' line will define the preferred +# method and so on. +# +# - if <key>=method, <info> contains +# + a method code --> mandatory, must be in the valid range +# + a prompt flag --> optional, identified by the key 'pt:', +# e.g. pt:yes +# values: 'yes' or 1, 'no' or '0' +# + a reuse flag --> optional, identified by the key 'ru:', +# e.g. ru:no +# values: 'yes' or 1, 'no' or '0' +# + some relevant information for authentication (optional, +# see below) +# +# The 'prompt' flag defines whether the user should be prompted +# for the relevant authentication details each time an +# authentication with the corresponding method is attempted. +# Default is 'yes', superseeded by the related entry in '.rootrc' . +# The 'reuse' flag determines if a successful authentication will +# be later re-used without prompting (e.g. when the user tries +# to access the same host with same method during the same +# session: this allows to speed up operation in case of multiple +# access). Default is 'yes' for methods 0 (UsrPwd), 3 (Globus) +# and 4 (SSH), superseeded by the related entries in '.rootrc'; +# feature not yet implemented for methods 1 (SRP) and 2 (Kerberos). +# No additional info is needed by method 5 (UidGid): this method +# sends to the remote host the (uid,gid) of the current process; +# 'reuse' will be af no advantage and 'prompt' is not allowed for +# security reasons. The format for the default info depends on +# the method: +# +# Method Format info +# +# UsrPwd us:<username> cp:<crypt_option> +# SRP us:<username> +# Kerberos us:<principal> +# Globus cd:<user_certkey_dir> +# cf:<usercert_file> +# kf:<userkey_file> +# ad:<authorities_dir> +# SSH us:<username> +# UidGid +# +# The additional keys for UsrPwd specify: +# 'cp' whether to encrypt the password with a public key (default) +# or not (slighty faster), values are 'yes' or '1' for YES, +# 'no' or '0' for NO (case sensitive); +# +# The keys for Globus allow to specify only partial changes of +# the defaults: +# 'cd' defines the directory containing the user certificate +# and private key files; +# 'cf' defines the user certificate file +# 'kf' defines the user private key file +# 'ad' defines the directory containing credentials for +# recognized Certificate Authorities +# (the CA signing the remote host certificate must have +# an entry here) +# All these files and directories can be specified as absolute +# paths (starting with '/') or as relative to the getenv("HOME") +# directory (starting with '~/') or relative to the local '.globus' +# directory. Defaults are: +# cd:~/.globus +# cf:usercert.pem +# kf:userkey.pem +# ad:/etc/grid-security/certificates +# +# NB: for all the mentioned keys, there should be NO space between +# the key and the value, e.g. 'us: qwerty' will result in +# <username>="" +# +# Example of valid 'method' lines: +# +# default method ssh pt:yes us:qwerty +# default method 3 pt:0 +# default user asdfgh method usrpwd pt:1 ru:no +# lxplus*.cern.ch method 3 pt:no ad:certificates +# pcepsft43.cern.ch user poiuyt method globus pt:no \ +# cd:~/CA/HubCA/poiuyt ad:certificates +# +# The first line specifies that when a SSH authentication is +# attempted, the user will be prompted for the remote username, +# with 'qwerty' as default. The second line states that for +# Globus the user will not be prompted and the credentials +# and related files will be looked for in the default places. +# The third line specifies that, for UsrPwd authentication, user +# 'asdfgh' will get a prompt with default username 'asdfgh' and +# that a successful authentication will not be reused +# The fourth line tells that for Globus to lxplus, the user +# will still not be prompted, but the credentials for the +# CA signing the remote certificate will be looked +# for in ~/.globus/certificates. +# The fifth line tells that for Globus authentication on +# pcepsft43 of user poiuyt, the usercert.pem and userkey.pem +# files are looked for in directory ~/CA/HubCA/poiuyt, +# and the credentials for the CA signing the remote certificate +# in ~/.globus/certificates. +# diff --git a/etc/hostcert.conf b/etc/hostcert.conf new file mode 100644 index 0000000000000000000000000000000000000000..d18e520535f1c69d4630b79622c8901d9cfe697b --- /dev/null +++ b/etc/hostcert.conf @@ -0,0 +1,7 @@ +# This is a comment ... +#/etc/grid-security/certificates /etc/grid-security/hostcert.pem /etc/grid-security/hostkey.pem /etc/grid-security/grid-mapfile1 +#/etc/grid-security/certificates /etc/grid-security/hostcert.pem /etc/grid-security/hostkey.pem +#/etc/grid-security/certificates /home/ganis/.globus/usercert.pem /home/ganis/.globus/userkey.pem +# /etc/grid-security/certificates /etc/grid-security/cernCA/hostcert.pem /etc/grid-security/cernCA/hostkey.pem +# This to try automatic completion ... +# /home/ganis/.globus/certificates diff --git a/etc/rpdauth.allow b/etc/rpdauth.allow new file mode 100644 index 0000000000000000000000000000000000000000..6d71dd05c65e5d6b3f5b031bccfd409319594cd8 --- /dev/null +++ b/etc/rpdauth.allow @@ -0,0 +1,79 @@ +# +# rpdauth.allow This file describes the names of the hosts for which +# the allowed authentication methods are not the default ones +# as specified in system.rootc (if any). +# This file is used by the 'rootd' and 'proofd' daemons. +# +# Format: +# - lines starting with '#' are comment lines. +# +# - hosts can specified either with their FQDN (eg, pcepsft43.cern.ch) or +# their IP address (eg 137.138.99.73). +# +# - the '*' character can be used in the first field of the name to +# indicate a set of machines, e.g. pcepsft*.cern.ch applies to all +# 'pcepsft' machines in the domain 'cern.ch' +# (to indicate all 'lxplus' machines you should use 'lxplus*.cern.ch' +# because internally the generic lxplus machine has a real name of +# the form lxplusnnn.cern.ch). +# +# - a whole domain can be indicated by its name, with at least two non +# null fields, eg 'cern.ch' or '.cern.ch' ; '.ch' is not accepted. +# +# - subsets of the IP address can also be used to indicate a set of +# machines, however, it is mandatory to end the subset with a '.', +# e.g. '137.138.' is an alternative way to indicate the 'cern.ch' +# domain, but '137.138' is invalid because ambiguous. +# +# - the information following the name or IP address indicates, in order +# of preference, the short names or the internal codes of authentication +# methods accepted for requests coming from the specified host(s); the +# ones implemented so far are: +# +# Method short name code +# +# UsrPwd usrpwd 0 +# SRP srp 1 +# Kerberos krb5 2 +# Globus globus 3 +# SSH ssh 4 +# UidGid uidgid 5 (insecure) +# +# (The insecure method is intended to speed up access within a cluster +# protected by other means from outside attacks; should not be used for +# intercluster or interdomain authentication). +# Methods non specified explicitly are not accepted. +# For the insecure method it is possible to give access only to a +# specific list of users by specifying the usernames after the method +# separated by colons (:) example: +# +# uidgid:user1:user2:user3 +# +# will allow uidgid access only to users user1, user2 and user3. +# This is useful to give easy access to data servers. +# +# It is also possible to deny access to a user by using a '-' in front of +# the name: +# +# uidgid:-user4 +# +# - Lines ending with '\' are followed by additional information for the +# host on the next line; the name of the host should not be repeated. +# +# Example of allowing machines in the cern.ch domain to authenticate +# using SSH (as preferred method) followed by the Globus and UsrPwd methods; +# in this case, attempts to use SRP, Kerberos or UidGid methods will be +# rejected; however, the accepted methods will be comunicated to the client +# and an automatic retry is attempted if the client can use any of them +# (negotiation). +# +# Valid examples: +# +# default none +# default ssh 0 uidgid +# 127.0.0.1 4 0 3 1 2 5 +# 137.138. 4 0 +# pceple19.cern.ch 4 1 3 2 5 0 +# lxplus*.cern.ch 4 1 globus 0:ganis:gganis 5 +# pcepsft43.cern.ch 4 3 1 5 2 0 +# afal57.cern.ch 0 5 4 diff --git a/globusauth/Module.mk b/globusauth/Module.mk new file mode 100644 index 0000000000000000000000000000000000000000..1c5b7d0120147b5f1912aba8aef8444e148a4f16 --- /dev/null +++ b/globusauth/Module.mk @@ -0,0 +1,67 @@ +# Module.mk for krb5 authentication module +# Copyright (c) 2002 Rene Brun and Fons Rademakers +# +# Author: Fons Rademakers, 18/3/2002 (for krb5auth) +# Mod by: Gerardo Ganis, 18/1/2003 + +MODDIR := globusauth +MODDIRS := $(MODDIR)/src +MODDIRI := $(MODDIR)/inc + +GLBSAUTHDIR := $(MODDIR) +GLBSAUTHDIRS := $(GLBSAUTHDIR)/src +GLBSAUTHDIRI := $(GLBSAUTHDIR)/inc + +##### libGlobusAuth ##### +GLBSAUTHH := $(wildcard $(MODDIRI)/*.h) +GLBSAUTHS := $(wildcard $(MODDIRS)/*.cxx) +GLBSAUTHO := $(GLBSAUTHS:.cxx=.o) + +GLBSAUTHDEP := $(GLBSAUTHO:.o=.d) + +GLBSAUTHLIB := $(LPATH)/libGlobusAuth.$(SOEXT) + +##### experimental patch ##### +GLBPATCHS := +GLBPATCHO := +GLBPATCHDEP := +ifneq ($(GLBPATCHFLAGS),) +GLBPATCHS := $(MODDIRS)/globus_gsi_system_config.c +GLBPATCHO := $(GLBPATCHS:.c=.o) +GLBPATCHDEP := $(GLBPATCHO:.o=.d) +endif + +# used in the main Makefile +ALLHDRS += $(patsubst $(MODDIRI)/%.h,include/%.h,$(GLBSAUTHH)) +ALLLIBS += $(GLBSAUTHLIB) + +# include all dependency files +INCLUDEFILES += $(GLBSAUTHDEP) + +##### local rules ##### +include/%.h: $(GLBSAUTHDIRI)/%.h + cp $< $@ + +$(GLBSAUTHLIB): $(GLBSAUTHO) $(GLBPATCHO) $(MAINLIBS) + @$(MAKELIB) $(PLATFORM) $(LD) "$(LDFLAGS)" \ + "$(SOFLAGS)" libGlobusAuth.$(SOEXT) $@ "$(GLBSAUTHO) $(GLBPATCHO)" \ + "$(GLBSAUTHLIBEXTRA) $(GLOBUSLIBDIR) $(GLOBUSLIB)" + +all-globusauth: $(GLBSAUTHLIB) + +clean-globusauth: + @rm -f $(GLBSAUTHO) + +clean:: clean-globusauth + +distclean-globusauth: clean-globusauth + @rm -f $(GLBSAUTHDEP) $(GLBSAUTHLIB) + +distclean:: distclean-globusauth + +##### extra rules ###### +$(GLBSAUTHO): %.o: %.cxx + $(CXX) $(OPT) $(CXXFLAGS) -I$(GLOBUSINCDIR) -I$(GLOBUSINCDIR)/gcc32dbg -I$(GLOBUSINCDIR)/gcc32dbgpthr -o $@ -c $< + +$(GLBPATCHO): %.o: %.c + $(CC) $(OPT) $(CFLAGS) $(GLBPATCHFLAGS) -I$(GLOBUSINCDIR) -I$(GLOBUSINCDIR)/gcc32dbg -I$(GLOBUSINCDIR)/gcc32dbgpthr -o $@ -c $< diff --git a/globusauth/src/GlobusAuth.cxx b/globusauth/src/GlobusAuth.cxx new file mode 100644 index 0000000000000000000000000000000000000000..18ca6573f3ac3669d67a6422ab1b1edb9b10c666 --- /dev/null +++ b/globusauth/src/GlobusAuth.cxx @@ -0,0 +1,1308 @@ +// @(#)root/globus:$Name:$:$Id:$ +// Author: Gerardo Ganis 15/01/2003 + +/************************************************************************* + * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +/* Parts of this file are adapted from the Globus Tool Kit version 2.2.3 + * are subject to related licenses. + * Please refer to www.globus.org for details + */ + +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> + +extern "C" { +#include <globus_gss_assist.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <sys/ipc.h> +#include <sys/shm.h> +} +#include "TSocket.h" +#include "TAuthenticate.h" +#include "THostAuth.h" +#include "TError.h" +#include "TSystem.h" +#include "TROOT.h" +#include "TApplication.h" +#include "TEnv.h" +#include "Getline.h" +#include "rpderr.h" +static gss_cred_id_t GlbDelCredHandle = GSS_C_NO_CREDENTIAL; +int gShmIdCred = -1; +char gConfDir[kMAXPATHLEN] = { 0 }; +static int gLocalCallEnv = -1; +char gUser[256] = { 0 }; + +int GlobusGetDelCred(); +void GlobusCleanup(); +void GlobusError(char *, OM_uint32, OM_uint32, int); +int GlobusStoreSecContext(char *, gss_ctx_id_t, char *); +int GlobusGetLocalEnv(int *, TString); +int GlobusGetNames(int, char **, char **); +int GlobusGetCredHandle(int, gss_cred_id_t *); +int GlobusCheckSecContext(char *, char *); +int GlobusUpdateSecContInfo(int); +void GlobusSetCertificates(int); + +Int_t GlobusAuthenticate(TAuthenticate *, TString &, TString &); + +class GlobusAuthInit { + public: + GlobusAuthInit() { + TAuthenticate::SetGlobusAuthHook(&GlobusAuthenticate); +}}; +static GlobusAuthInit globusauth_init; + +// For established Security Contexts +static char **hostGlbSecCont = 0; +static char **subjGlbSecCont = 0; +static gss_ctx_id_t *sptrGlbSecCont = 0; +static int NumGlbSecCont = 0; + +// OffSet in Auth Tab remote file +TString gDetails; +static int gNeedProxy = 1; +char gPromptReUse[20]; +Int_t gPrompt = 0; +Int_t gRSAKey = 0; + +TSocket *sock = 0; +THostAuth *HostAuth = 0; +TString protocol; + +//______________________________________________________________________________ +Int_t GlobusAuthenticate(TAuthenticate * Auth, TString & user, + TString & details) +{ + // Globus authentication code. + // Returns 0 in case authentication failed + // 1 in case of success + // 2 in case of the remote node doesn not seem to support Globus Authentication + // 3 in case of the remote node doesn not seem to have certificates for our CA + + int auth = 0, rc; + int retval = 0, kind = 0, type = 0, server_auth = 0, brcv = 0, bsnd = 0; + gss_cred_id_t GlbCredHandle = GSS_C_NO_CREDENTIAL; + gss_ctx_id_t GlbContextHandle = GSS_C_NO_CONTEXT; + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + OM_uint32 GssRetFlags = 0; + OM_uint32 GssReqFlags = 0; + int GlbTokenStatus = 0; + char *isuj = 0; + char *ssuj = 0; + char *host_subj = 0; + gss_buffer_desc OutBuf; + + // From the calling TAuthenticate + sock = Auth->GetSocket(); + HostAuth = Auth->GetHostAuth(); + protocol = Auth->GetProtocol(); + + if (gDebug > 2) + Info("GlobusAuthenticate", " enter: %s %s", protocol.Data(), + user.Data()); + + // If we are called for local cleanup, do it and return ... + if (protocol == "cleanup") { + GlobusCleanup(); + return 1; + } + // Check ReUse + Int_t ReUse = 1; + if (gSystem->Getenv("AUTHREUSE") != 0 && + !strcmp(gSystem->Getenv("AUTHREUSE"), "0")) + ReUse = 0; + gPrompt = 0; + if (gSystem->Getenv("PROMPTUSER") != 0) { + sprintf(gPromptReUse, "pt:%s ru:%d", gSystem->Getenv("PROMPTUSER"), + ReUse); + if (!strcmp(gSystem->Getenv("PROMPTUSER"), "1")) + gPrompt = 1; + } else { + sprintf(gPromptReUse, "pt:1 ru:%d", ReUse); + } + + // The host FQDN ... for debugging + const char *hostFQDN = sock->GetInetAddress().GetHostName(); + + // Determine local calling environment ... + if ((rc = GlobusGetLocalEnv(&gLocalCallEnv, protocol))) { + Error("GlobusAuthenticate", + "PROOF Master: unable to set relevant environment variables (rc=%d)", + rc); + return -1; + } + if (gDebug > 3) + Info("GlobusAuthenticate", " gLocalCallEnv is %d", gLocalCallEnv); + + // Set local certificates according to user requests ... + GlobusSetCertificates(gLocalCallEnv); + + // Now we send to the rootd/proofd daemons the issuer name of our globus certificates .. + // We get it the x509 relevant certificate ... the location depends on the calling environment + char *stmp; + if ((rc = GlobusGetNames(gLocalCallEnv, &isuj, &stmp))) { + Error("GlobusAuthenticate", + "PROOF Master: unable to determine relevant names(rc=%d)", rc); + return -1; + } + if (gDebug > 2) + Info("GlobusAuthenticate", " Issuer name is %s (%d)", isuj, + strlen(isuj)); + SafeDelete(stmp); + + // Get credential handle ... either genuine or delegated + if (GlobusGetCredHandle(gLocalCallEnv, &GlbCredHandle)) { + Error("GlobusAuthenticate", "unable to acquire valid credentials"); + return -1; + } + if (gDebug > 3) + Info("GlobusAuthenticate", " Credential Handle is 0x%x", + GlbCredHandle); + + // Inquire credentials for Subject name and convert it in human readable form ... + gss_name_t Name; + OM_uint32 LifeTime; + gss_cred_usage_t CredUsage; + gss_OID_set Mech; + gss_OID NameType; + if ((MajStat = + gss_inquire_cred(&MinStat, GlbCredHandle, &Name, &LifeTime, + &CredUsage, &Mech)) != GSS_S_COMPLETE) { + GlobusError("GlobusAuthenticate: gss_inquire_cred", MajStat, MinStat, + 0); + return -1; + } + if ((MajStat = + gss_display_name(&MinStat, Name, &OutBuf, + &NameType)) != GSS_S_COMPLETE) { + GlobusError("GlobusAuthenticate: gss_inquire_cred", MajStat, MinStat, + 0); + return -1; + } else { + ssuj = StrDup((char *) OutBuf.value); + } + if (gDebug > 2) + Info("GlobusAuthenticate", " Subject name is %s (%d)", ssuj, + strlen(ssuj)); + + // Create Options string + char *Options = new char[strlen(ssuj) + 20]; + int Opt = ReUse * kAUTH_REUSE_MSK; + if (GlobusCheckSecContext((char *) hostFQDN, ssuj) > -1) { + sprintf(Options, "%d %d %s", Opt, strlen(ssuj), ssuj); + } else { + sprintf(Options, "%d 4 None", Opt); + } + + // Check established authentications + kind = kROOTD_GLOBUS; + retval = ReUse; + rc = 0; + if ((rc = + TAuthenticate::AuthExists(Auth, (Int_t) TAuthenticate::kGlobus, + gDetails, Options, &kind, + &retval)) == 1) { + // A valid authentication exists: we are done ... + SafeDelete(Options); + return 1; + } + if (rc == -2) { + SafeDelete(Options); + return rc; + } + // If server does not support Globus authentication we can't continue ... + if (retval == 0 || kind != kROOTD_GLOBUS) { + if (gDebug > 2) + Info("GlobusAuthenticate", " got retval: %d kind: %d from server", + retval, kind); + return 2; + } + // Now we send the issuer to the server daemon + char *buf = new char[20]; + sprintf(buf, "%d", (int) (strlen(isuj) + 1)); + if ((bsnd = sock->Send(buf, kMESS_STRING)) != (int) (strlen(buf) + 1)) { + Error("GlobusAuthenticate", + "Length of Issuer name not send correctly: bytes sent: %d (tot len: %d)", + bsnd - 1, strlen(buf)); + return 0; + } + SafeDelete(buf); + // Now we send it to the server daemon + if ((bsnd = sock->Send(isuj, kMESS_STRING)) != (int) (strlen(isuj) + 1)) { + Error("GlobusAuthenticate", + "Issuer name not send correctly: bytes sent: %d (tot len: %d)", + bsnd - 1, strlen(isuj)); + return 0; + } + // Now we wait for the replay from the server ... + sock->Recv(retval, kind); + if (kind != kROOTD_GLOBUS) { + Error("GlobusAuthenticate", + "recv host subj: unexpected message from daemon: kind: %d (expecting: %d)", + kind, kROOTD_GLOBUS); + } else { + if (retval == 0) { + Error("GlobusAuthenticate", + "recv host subj: host not able to authenticate this CA"); + return 3; + } else { + if (gDebug > 3) + Info("GlobusAuthenticate", + "recv host subj: buffer length is: %d", retval); + host_subj = new char[retval + 1]; + brcv = sock->Recv(host_subj, retval, kind); + if (brcv < (retval - 1)) { + Error("GlobusAuthenticate", + "recv host subj: did not receive all the bytes (recv: %d, due >%d)", + brcv, retval); + Error("GlobusAuthenticate", "recv host subj: (%d) %s", + strlen(host_subj), host_subj); + return 0; + } + } + } + // Now we have a valid subject name for the host ... + if (gDebug > 2) + Info("GlobusAuthenticate", "Host subject: %s", host_subj); + + // We need to associate a FILE* stream with the socket + // It will automatically closed when the socket will be closed ... + int SockFd = sock->GetDescriptor(); + FILE *FILE_SockFd = fdopen(SockFd, "w+"); + + + // Type of request for credentials depend on calling environment + GssReqFlags = + gLocalCallEnv > + 0 ? (GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG) : GSS_C_MUTUAL_FLAG; + if (gDebug > 3) + Info("GlobusAuthenticate", + " GssReqFlags: 0x%x, GlbCredentials: 0x%x", GssReqFlags, + (int) GlbCredHandle); + + // Now we are ready to start negotiating with the Server + if ((MajStat = + globus_gss_assist_init_sec_context(&MinStat, GlbCredHandle, + &GlbContextHandle, host_subj, + GssReqFlags, &GssRetFlags, + &GlbTokenStatus, + globus_gss_assist_token_get_fd, + (void *) FILE_SockFd, + globus_gss_assist_token_send_fd, + (void *) FILE_SockFd)) != + GSS_S_COMPLETE) { + GlobusError("GlobusAuthenticate: gss_assist_init_sec_context", + MajStat, MinStat, GlbTokenStatus); + SafeDelete(host_subj); + return 0; + } else { + GlobusStoreSecContext((char *) hostFQDN, GlbContextHandle, ssuj); + if (gDebug > 2) + Info("GlobusAuthenticate", "authenticated to host %s", hostFQDN); + if (fflush(FILE_SockFd) != 0) { + Warning("GlobusAuthenticate", + "unable to fflush socket: may cause Auth problems on server side\n"); + } + auth = 1; + } + + // Now we have the subject and we can release some resources ... + SafeDelete(host_subj); + + // Receive username used for login or key request info and type of key + int nrec = sock->Recv(retval, type); // returns user + + if (ReUse == 1) { + + if (type != kROOTD_RSAKEY) + Warning("GlobusAuthenticate", + "problems recvn RSA key flag: got message %d, flag: %d", + type, gRSAKey); + gRSAKey = 1; + + // RSA key generation (one per session) + if (!TAuthenticate::GetRSAInit()) { + Auth->GenRSAKeys(); + TAuthenticate::SetRSAInit(); + } + // Send key + if (gDebug > 3) + Info("GlobusAuthenticate", "Sending Local Key:\n '%s'", + TAuthenticate::GetRSAPubExport()); + sock->Send(TAuthenticate::GetRSAPubExport(), kROOTD_RSAKEY); + + // Receive username used for login + nrec = sock->Recv(retval, type); // returns user + } + + if (type != kROOTD_GLOBUS || retval < 1) + Warning("GlobusAuthenticate", + "problems recvn (user,offset) length (%d:%d bytes:%d)", type, + retval, nrec); + char *rfrm = new char[retval + 1]; + nrec = sock->Recv(rfrm, retval + 1, type); // returns user + if (type != kMESS_STRING) + Warning("GlobusAuthenticate", + "username and offset not received (%d:%d)", type, nrec); + else if (gDebug > 2) + Info("GlobusAuthenticate", "logging remotely as %s ", rfrm); + + // Parse answer + char *lUser = new char[retval]; + Int_t OffSet = -1; + sscanf(rfrm, "%s %d", lUser, &OffSet); + + // Return username + user = lUser; + // Keep track of remote login username ... + strcpy(gUser, lUser); + + // Receive Token + char *Token = 0; + if (ReUse == 1 && OffSet > -1) { + if (TAuthenticate::SecureRecv(sock, gRSAKey, &Token) == -1) { + Warning("SRPAuthenticate", + "Problems secure-receiving Token - may result in corrupted Token"); + } + if (gDebug > 3) + Info("GlobusAuthenticate", "received from server: token: '%s' ", + Token); + } else { + Token = StrDup(""); + } + + // Create and save AuthDetails object + TAuthenticate::SaveAuthDetails(Auth, (Int_t) TAuthenticate::kGlobus, + OffSet, ReUse, gDetails, lUser, gRSAKey, + Token); + details = gDetails; + + // receive status from server + sock->Recv(server_auth, kind); + if (gDebug > 2) + Info("GlobusAuthenticate", "received auth status from server: %d ", + server_auth); + + if (auth && !server_auth) + Warning("GlobusAuthenticate", + " it looks like server did not authenticate "); + + // free allocated memory ... + SafeDelete(isuj); + SafeDelete(ssuj); + SafeDelete(rfrm); + SafeDelete(lUser); + SafeDelete(Token); + + // return result + return auth; +} + +//______________________________________________________________________________ +int GlobusGetDelCred() +{ + // This function fetchs from the shared memory segment created by 'proofd'. + // the delegated credentials needed to autheticate the slaves ... + // The shared memory segment is destroyed. + + struct shmid_ds shm_ds; + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + + if (gDebug > 2) + Info("GlobusGetDelCred:", "Enter ..."); + + // Attach segment to address + gss_buffer_t databuf = (gss_buffer_t) shmat(gShmIdCred, 0, 0); + + // Import credentials + // credential= (gss_buffer_t)malloc(sizeof(gss_buffer_desc)+databuf->length); + gss_buffer_t credential = + (gss_buffer_t) new char[sizeof(gss_buffer_desc) + databuf->length]; + credential->length = databuf->length; + credential->value = + (void *) ((char *) credential + sizeof(size_t) + sizeof(void *)); + void *dbufval = + (void *) ((char *) databuf + sizeof(size_t) + sizeof(void *)); + memmove(credential->value, dbufval, credential->length); + if ((MajStat = + gss_import_cred(&MinStat, &GlbDelCredHandle, 0, 0, credential, 0, + 0)) != GSS_S_COMPLETE) { + GlobusError("GlobusGetDelCred: gss_import_cred", MajStat, MinStat, + 0); + return 1; + } else if (gDebug > 3) + Info("GlobusGetDelCred:", + "Globus Credentials successfully imported (0x%x)", + GlbDelCredHandle); + + SafeDelete(credential); + + // Detach from shared memory segment + int rc = shmdt((const void *) databuf); + if (rc != 0) { + if (gDebug > 0) + Info("GlobusGetDelCred:", + "unable to detach from shared memory segment (rc=%d)", rc); + } + if (gDebug > 3) { + rc = shmctl(gShmIdCred, IPC_STAT, &shm_ds); + Info("GlobusGetDelCred:", + "Process: uid: %d, euid: %d - Buffer: uid: %d, cuid: %d", + getuid(), geteuid(), shm_ds.shm_perm.uid, shm_ds.shm_perm.cuid); + } + + rc = shmctl(gShmIdCred, IPC_RMID, &shm_ds); + if (rc == 0) { + if (gDebug > 2) + Info("GlobusGetDelCred:", + "shared memory segment successfully marked as destroyed"); + } else { + Warning("GlobusGetDelCred:", + "unable to mark segment %d as destroyed", gShmIdCred); + } + + return 0; +} + +//______________________________________________________________________________ +void GlobusError(char *mess, OM_uint32 majs, OM_uint32 mins, int toks) +{ + // Handle error ... + + char *GlbErr; + + if (!globus_gss_assist_display_status_str + (&GlbErr, mess, majs, mins, toks)) { + } else { + GlbErr = new char[kMAXPATHLEN]; + sprintf(GlbErr, "%s: error messaged not resolved ", mess); + } + Error(":Error: %s (majst=%d,minst=%d,tokst:%d)", GlbErr, majs, mins, + toks); + + SafeDelete(GlbErr); +} + +//______________________________________________________________________________ +int GlobusStoreSecContext(char *host, gss_ctx_id_t context_handle, + char *client_name) +{ + // Store relevant info about an established security context for later use. + // On success returns number of stored security contexts; 0 otherwise. + + if (gDebug > 2) + Info("GlobusStoreSecContext", "Enter: %s", host); + + // Now we can count it + NumGlbSecCont++; + + if (NumGlbSecCont > 1) { + char **tmph = hostGlbSecCont; + char **tmpc = subjGlbSecCont; + gss_ctx_id_t *tmps = sptrGlbSecCont; + + hostGlbSecCont = new char *[NumGlbSecCont]; + subjGlbSecCont = new char *[NumGlbSecCont]; + sptrGlbSecCont = new gss_ctx_id_t[NumGlbSecCont]; + + int i; + for (i = 0; i < NumGlbSecCont - 1; i++) { + hostGlbSecCont[i] = strdup(tmph[i]); + subjGlbSecCont[i] = strdup(tmpc[i]); + sptrGlbSecCont[i] = tmps[i]; + + } + + hostGlbSecCont[NumGlbSecCont - 1] = strdup(host); + subjGlbSecCont[NumGlbSecCont - 1] = strdup(client_name); + sptrGlbSecCont[NumGlbSecCont - 1] = context_handle; + + SafeDelete(tmph); + SafeDelete(tmpc); + SafeDelete(tmps); + + } else { + + hostGlbSecCont = new char *[NumGlbSecCont]; + subjGlbSecCont = new char *[NumGlbSecCont]; + sptrGlbSecCont = new gss_ctx_id_t[NumGlbSecCont]; + hostGlbSecCont[NumGlbSecCont - 1] = strdup(host); + subjGlbSecCont[NumGlbSecCont - 1] = strdup(client_name); + sptrGlbSecCont[NumGlbSecCont - 1] = context_handle; + } + + if (gDebug > 2) { + int isave = NumGlbSecCont - 1; + Info("GlobusStoreSecContext", + "stored new sec context (session: %d, no:%d, ctx_id_t:0x%x) for client %s for host %s", + getpid(), NumGlbSecCont, sptrGlbSecCont[isave], + subjGlbSecCont[isave], hostGlbSecCont[isave]); + } + + return NumGlbSecCont; +} + +//______________________________________________________________________________ +int GlobusGetLocalEnv(int *LocalEnv, TString protocol) +{ + // Determines calling environment. + // Returns 0 if successful; 1 otherwise. + + int retval = 0; + + // Calling application + TApplication *lApp = gROOT->GetApplication(); + if (gDebug > 2) { + int i = 0; + for (; i < lApp->Argc(); i++) { + Info("GlobusGetLocalEnv", " Application arguments: %d: %s", i, + lApp->Argv()[i]); + } + } + + *LocalEnv = 0; + if (lApp != 0) { + if (strstr(lApp->Argv()[1], "proof") != 0) { + // This is PROOF ... either Master or Slave ... + if (gDebug > 3) { + Info("GlobusGetLocalEnv", + " PROOF environment, called by the MASTER/SLAVE"); + Info("GlobusGetLocalEnv", + " String with Pointer to del cred is 0x%x", + GlbDelCredHandle); + } + *LocalEnv = 2; + strncpy(gConfDir, lApp->Argv()[2], strlen(lApp->Argv()[2]) + 1); + gShmIdCred = atoi(lApp->Argv()[7]); + if (setenv("X509_CERT_DIR", lApp->Argv()[8], 1)) { + Error("GlobusGetLocalEnv", + "PROOF Master: unable to set X509_CERT_DIR "); + retval = 1; + } + if (setenv("X509_USER_CERT", lApp->Argv()[9], 1)) { + Error("GlobusGetLocalEnv", + "PROOF Master: unable to set X509_USER_CERT "); + retval = 2; + } + if (setenv("X509_USER_KEY", lApp->Argv()[10], 1)) { + Error("GlobusGetLocalEnv", + "PROOF Master: unable to set X509_USER_KEY "); + retval = 3; + } + } else { + if (strstr(protocol.Data(), "proof") != 0) { + if (gDebug > 3) + Info("GlobusGetLocalEnv", + " PROOF environment, called by the CLIENT"); + *LocalEnv = 1; + } else if (strstr(protocol.Data(), "root") != 0) { + if (gDebug > 3) + Info("GlobusGetLocalEnv", " ROOT environment"); + } else { + Warning("GlobusGetLocalEnv", + " Unable to recognize the environment (protocol: %s)-> assume ROOT", + protocol.Data()); + } + } + } else { + Warning("GlobusGetLocalEnv", + " Unable to get pointer to current application -> assume ROOT environment"); + } + + return retval; +} + +//______________________________________________________________________________ +int GlobusGetNames(int LocalEnv, char **IssuerName, char **SubjectName) +{ + // Get Issuer and Client Names from local certificates. + // Returns 0 is successfull, 1 otherwise. + + char *usercert_default = "/.globus/usercert.pem"; + char *cert_file = 0; + X509 *xcert = 0; + + if (gDebug > 2) + Info("GlobusGetNames", "Enter: LocalEnv: %d", LocalEnv); + + int retval = 0; + + if (LocalEnv == 2) { + // We are a Proof master: the location is given by X509_USER_CERT ... if not exit; + if (getenv("X509_USER_CERT") != 0) { + int lcf = strlen(getenv("X509_USER_CERT")); + cert_file = new char[lcf]; + strncpy(cert_file, getenv("X509_USER_CERT"), lcf + 1); + } else { + Error("GlobusGetNames", + "PROOF Master: host certificate not defined"); + retval = 1; + } + } else { + // We are a client: determine the location for user certificate ... + if (getenv("X509_USER_CERT") != 0) { + int lcf = strlen(getenv("X509_USER_CERT")); + cert_file = new char[lcf]; + strncpy(cert_file, getenv("X509_USER_CERT"), lcf + 1); + } else { + char *userhome = getenv("HOME"); + cert_file = + new char[strlen(userhome) + strlen(usercert_default) + 1]; + strncpy(cert_file, userhome, strlen(userhome) + 1); + strncpy(cert_file + strlen(cert_file), usercert_default, + strlen(usercert_default) + 1); + } + } + + // Test the existence of the certificate file // + if (access(cert_file, F_OK)) { + Error("GlobusGetNames", "requested file %s does not exist", + cert_file); + // retval= 2; + SafeDelete(cert_file); + return 2; + } else if (access(cert_file, R_OK)) { + Error("GlobusGetNames", "no permission to read requested file %s", + cert_file); + // retval= 4; + SafeDelete(cert_file); + return 4; + } else if (gDebug > 3) { + Info("GlobusGetNames", "File with certificate: %s", cert_file); + } + // Second: load the certificate ... + FILE *fcert = fopen(cert_file, "r"); + if (fcert == 0 || !PEM_read_X509(fcert, &xcert, 0, 0)) { + Error("GlobusGetNames", "Unable to load user certificate "); + SafeDelete(cert_file); + return 5; + } + fclose(fcert); + + // Get the issuer name + *IssuerName = + StrDup(X509_NAME_oneline(X509_get_issuer_name(xcert), 0, 0)); + // Get the subject name + *SubjectName = + StrDup(X509_NAME_oneline(X509_get_subject_name(xcert), 0, 0)); + + if (gDebug > 2) { + Info("GlobusGetNames", "Issuer Name: %s", *IssuerName); + Info("GlobusGetNames", "Subject Name: %s", *SubjectName); + } + + SafeDelete(cert_file); + + // Now check if there is a proxy file associated with this user + int nProxy = 1; + gNeedProxy = 1; + char proxy_file[256]; + sprintf(proxy_file, "/tmp/x509up_u%d", getuid()); + again: + + if (gDebug > 3) + Info("GlobusGetNames", "Testing Proxy file: %s", proxy_file); + + if (!access(proxy_file, F_OK) && !access(proxy_file, R_OK)) { + // Second: load the proxy certificate ... + fcert = fopen(proxy_file, "r"); + if (fcert == 0 || !PEM_read_X509(fcert, &xcert, 0, 0)) { + Error("GlobusGetNames", "Unable to load user proxy certificate "); + return 5; + } + fclose(fcert); + // Get proxy names + char *ProxyIssuerName = + StrDup(X509_NAME_oneline(X509_get_issuer_name(xcert), 0, 0)); + char *ProxySubjectName = + StrDup(X509_NAME_oneline(X509_get_subject_name(xcert), 0, 0)); + if (gDebug > 3) { + Info("GlobusGetNames", "Proxy Issuer Name: %s", ProxyIssuerName); + Info("GlobusGetNames", "Proxy Subject Name: %s", + ProxySubjectName); + } + + if (strstr(ProxyIssuerName, *SubjectName) == ProxyIssuerName) { + gNeedProxy = 0; + setenv("X509_USER_PROXY", proxy_file, 1); + SafeDelete(ProxyIssuerName); + SafeDelete(ProxySubjectName); + if (gDebug > 3) + Info("GlobusGetNames", "Using Proxy file:%s (gNeedProxy:%d)", + getenv("X509_USER_PROXY"), gNeedProxy); + + return retval; + } else { + sprintf(proxy_file, "/tmp/x509up_u%d.%d", getuid(), nProxy); + nProxy++; + SafeDelete(ProxyIssuerName); + SafeDelete(ProxySubjectName); + goto again; + } + } else { + setenv("X509_USER_PROXY", proxy_file, 1); + return retval; + } + + return retval; +} + +//______________________________________________________________________________ +int GlobusGetCredHandle(int LocalEnv, gss_cred_id_t * CredHandle) +{ + // Get Credential Handle, either from scratch, or from delegated info ... + // Returns 0 is successfull, 1 otherwise. + + int retval = 0; + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + + if (gDebug > 2) + Info("GlobusGetCredHandle", "Enter: LocalEnv: %d", LocalEnv); + + if (LocalEnv == 2) { + // If we are a PROOF Master autheticating vs Slaves we only need to fetch the delegated + // credentials from the shared memory segment the first time we are called ... + if (GlbDelCredHandle == GSS_C_NO_CREDENTIAL) { + if (GlobusGetDelCred()) { + Error("GlobusGetCredHandle", + "unable to fetch valid credentials from the shared memory segment"); + retval = 1; + goto exit; + } + } + *CredHandle = GlbDelCredHandle; + } else { + + // Inquire Globus credentials: + // This is looking to file X509_USER_PROXY for valid a X509 cert + // (default /tmp/x509up_u<uid> ) + if ((gNeedProxy == 1) || + (MajStat = + globus_gss_assist_acquire_cred(&MinStat, GSS_C_INITIATE, + CredHandle)) != GSS_S_COMPLETE) { + + // Check if interactive session + TApplication *lApp = gROOT->GetApplication(); + if (strstr(lApp->Argv()[1], "proof") == 0) { + + if (gDebug > 3) + Info("GlobusGetCredHandle", + "Failed to acquire credentials: trying to initialize proxies ..."); + + // Try to get credentials with usual command line ... + char *GlobusLocation = getenv("GLOBUS_LOCATION"); + if (GlobusLocation == 0) { + Error("GlobusGetCredHandle", + "Please define a valid GLOBUS_LOCATION"); + retval = 2; + goto exit; + } + // First check if there are special requests for proxy duration ... + const char *duration = + gEnv->GetValue("Globus.ProxyDuration", "default"); + char initdur[256] = { 0 }; + if (strstr(duration, "default") == 0) { + sprintf(initdur, "-hours %s", duration); + } + if (gDebug > 3) + Info("GlobusAutheticate", "initdur: %s (%s)", initdur, + duration); + + // ... and for number of bits in key ... + const char *keybits = + gEnv->GetValue("Globus.ProxyKeyBits", "default"); + char initbit[256] = { 0 }; + if (strstr(keybits, "default") == 0) { + sprintf(initbit, "-bits %s", keybits); + } + if (gDebug > 3) + Info("GlobusAutheticate", "initbit: %s (%s)", initbit, + keybits); + + // ... and for number of bits in key ... + char *usrpxy = getenv("X509_USER_PROXY"); + char initpxy[256] = { 0 }; + sprintf(initpxy, "-out %s", usrpxy); + if (gDebug > 3) + Info("GlobusAutheticate", "initpxy: %s (%s)", initpxy, + usrpxy); + + // ... and environment variables + char *cerdir = getenv("X509_CERT_DIR"); + char *usrcer = getenv("X509_USER_CERT"); + char *usrkey = getenv("X509_USER_KEY"); + char initenv[kMAXPATHLEN] = { 0 }; + sprintf(initenv, + "export X509_CERT_DIR=%s; export X509_USER_CERT=%s; export X509_USER_KEY=%s", + cerdir, usrcer, usrkey); + + // to execute command to initiate the proxies one needs to source the globus shell environment + char proxyinit[kMAXPATHLEN] = { 0 }; + sprintf(proxyinit, + "source $GLOBUS_LOCATION/etc/globus-user-env.sh; %s; grid-proxy-init %s %s %s", + initenv, initdur, initbit, initpxy); + if (gDebug > 3) + Info("GlobusAutheticate", "Executing: %s", proxyinit); + gSystem->Exec(proxyinit); + + // retry now + if ((MajStat = + globus_gss_assist_acquire_cred(&MinStat, GSS_C_INITIATE, + CredHandle)) != + GSS_S_COMPLETE) { + GlobusError("GlobusGetCredHandle: gss_assist_acquire_cred", + MajStat, MinStat, 0); + retval = 3; + goto exit; + } + } else { + Warning("GlobusGetCredHandle", + "proofserv: cannot prompt for credentials: returning failure"); + retval = 3; + goto exit; + } + } + } + + exit: + return retval; +} + +//______________________________________________________________________________ +int GlobusCheckSecContext(char *Host, char *SubjName) +{ + // Checks if there is already a valid security context established with + // remote host for subject ... + // On success returns entry number, -1 otherwise. + + int retval = -1; + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + OM_uint32 GssRetFlags = 0; + OM_uint32 GlbContLifeTime = 0; + + if (gDebug > 2) { + Info("GlobusCheckSecContext", "contacting host: %s", Host); + Info("GlobusCheckSecContext", + "we have got %d sec context handles in memory", NumGlbSecCont); + } + + if (NumGlbSecCont > 0) { + int i; + for (i = 0; i < NumGlbSecCont; i++) { + if (!strcmp(hostGlbSecCont[i], Host) + && !strcmp(subjGlbSecCont[i], SubjName)) { + if (gDebug > 3) + Info("GlobusCheckSecContext", + "we already have a sec context with host: %s for subj: %s", + Host, SubjName); + + // Check validity of the retrieved context ... + int Dum1, Dum2; + gss_OID MechType; + gss_name_t *TargName = 0, *Name = 0; + if (sptrGlbSecCont[i] != 0 + && sptrGlbSecCont[i] != GSS_C_NO_CONTEXT) { + if ((MajStat = + gss_inquire_context(&MinStat, sptrGlbSecCont[i], Name, + TargName, &GlbContLifeTime, + &MechType, &GssRetFlags, &Dum1, + &Dum2)) != GSS_S_COMPLETE) { + GlobusError("GlobusCheckSecContext: gss_inquire_context", + MajStat, MinStat, 0); + GlobusUpdateSecContInfo(i); // delete it from tables ... + } else { + if (gDebug > 3) + Info("GlobusCheckSecContext", + "client (%s) already authenticated from host %s (remaining lifetime: %d sec)", + SubjName, Host, GlbContLifeTime); + retval = i; + } + } + } + } + } + return retval; +} + +//______________________________________________________________________________ +int GlobusUpdateSecContInfo(int entry) +{ + // Removes entries corresponding to expired, unvalid or deleted security + // context. If entry=0 check the validity; if entry>0 remove 'entry' + // without checking. Returns number of valid sec contexts established. + + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + OM_uint32 GssRetFlags = 0; + OM_uint32 GlbContLifeTime = 0; + int nGoodCont = 0; + char **Hosts = new char *[NumGlbSecCont]; + char **Clien = new char *[NumGlbSecCont]; + gss_ctx_id_t *SCPtr = new gss_ctx_id_t[NumGlbSecCont]; + + if (gDebug > 2) + Info("GlobusUpdateSecContInfo", "Enter: entry: %d", entry); + + int i; + for (i = 0; i < NumGlbSecCont; i++) { + if (entry == 0) { + int Dum1, Dum2; + gss_OID MechType; + gss_name_t *TargName = 0, *client_name = 0; + + // Check validity of the retrieved context ... + if (sptrGlbSecCont[i] != 0 + && sptrGlbSecCont[i] != GSS_C_NO_CONTEXT) { + if ((MajStat = + gss_inquire_context(&MinStat, sptrGlbSecCont[i], + client_name, TargName, + &GlbContLifeTime, &MechType, + &GssRetFlags, &Dum1, + &Dum2)) != GSS_S_COMPLETE) { + GlobusError("GlobusUpdateSecContInfo: gss_inquire_context", + MajStat, MinStat, 0); + } else { + // This is a valid one ... + Hosts[nGoodCont] = strdup(hostGlbSecCont[i]); + Clien[nGoodCont] = strdup(subjGlbSecCont[i]); + SCPtr[nGoodCont] = sptrGlbSecCont[i]; + nGoodCont++; + } + } + } else if (entry != i) { + Hosts[nGoodCont] = strdup(hostGlbSecCont[i]); + Clien[nGoodCont] = strdup(subjGlbSecCont[i]); + SCPtr[nGoodCont] = sptrGlbSecCont[i]; + nGoodCont++; + } + } + + // Update reference table + SafeDelete(hostGlbSecCont); + SafeDelete(subjGlbSecCont); + SafeDelete(sptrGlbSecCont); + NumGlbSecCont = nGoodCont; + + if (NumGlbSecCont > 0) { + + if (gDebug > 3) + Info("GlobusUpdateSecContInfo", + " %d valid established security contexts found"); + + hostGlbSecCont = new char *[NumGlbSecCont]; + subjGlbSecCont = new char *[NumGlbSecCont]; + sptrGlbSecCont = new gss_ctx_id_t[NumGlbSecCont]; + + for (i = 0; i < NumGlbSecCont; i++) { + hostGlbSecCont[i] = strdup(Hosts[i]); + subjGlbSecCont[i] = strdup(Clien[i]); + sptrGlbSecCont[i] = SCPtr[i]; + if (gDebug > 3) + Info("GlobusUpdateSecContInfo", + "Sec cont %d for subject %s with host %s", i, Clien[i], + Hosts[i]); + } + } else if (gDebug > 3) { + Info("GlobusUpdateSecContInfo", + "No valid established security contexts remains"); + } + + return nGoodCont; +} + +//______________________________________________________________________________ +void GlobusSetCertificates(int LocalEnv) +{ + // Defines certificate and key files to use, inquiring the client if needed. + + char *userhome = getenv("HOME"); + char *globusdef = ".globus"; + char *details = 0; + Int_t nr, i; + TApplication *lApp = gROOT->GetApplication(); + + if (gDebug > 2) + Info("GlobusSetCertificates", "Enter: LocalEnv: %d", LocalEnv); + + gDetails = ""; + + if (LocalEnv < 2) { + + char temp[kMAXPATHLEN] = { 0 }; + + // Defaults + char tmpvar[4][kMAXPATHLEN]; + char *ddir = 0, *dcer = 0, *dkey = 0, *dadi = 0; + if (getenv("DEFAULTUSER") != 0) { + details = getenv("DEFAULTUSER"); + } else { + details = + "cd:~/.globus cf:usercert.pem kf:userkey.pem ad:/etc/grid-security/certificates"; + } + + if (gDebug > 3) + Info("GlobusSetCertificates", " details : %s", details); + + nr = sscanf(details, "%s %s %s %s", tmpvar[0], tmpvar[1], tmpvar[2], + tmpvar[3]); + for (i = 0; i < nr; i++) { + if (!strncmp(tmpvar[i], "cd:", 3) || !strncmp(tmpvar[i], "Cd:", 3) + || !strncmp(tmpvar[i], "cD:", 3) + || !strncmp(tmpvar[i], "CD:", 3)) + ddir = StrDup(tmpvar[i] + 3); + if (!strncmp(tmpvar[i], "cf:", 3) || !strncmp(tmpvar[i], "Cf:", 3) + || !strncmp(tmpvar[i], "cF:", 3) + || !strncmp(tmpvar[i], "CF:", 3)) + dcer = StrDup(tmpvar[i] + 3); + if (!strncmp(tmpvar[i], "kf:", 3) || !strncmp(tmpvar[i], "Kf:", 3) + || !strncmp(tmpvar[i], "kF:", 3) + || !strncmp(tmpvar[i], "KF:", 3)) + dkey = StrDup(tmpvar[i] + 3); + if (!strncmp(tmpvar[i], "ad:", 3) || !strncmp(tmpvar[i], "Ad:", 3) + || !strncmp(tmpvar[i], "aD:", 3) + || !strncmp(tmpvar[i], "AD:", 3)) + dadi = StrDup(tmpvar[i] + 3); + } + if (ddir == 0) + ddir = StrDup("~/.globus"); + if (dcer == 0) + dcer = StrDup("usercert.pem"); + if (dkey == 0) + dkey = StrDup("userkey.pem"); + if (dadi == 0) + dadi = StrDup("/etc/grid-security/certificates"); + + // Check if needs to prompt the client + char *det = 0; + if (gPrompt) { + char *dets = 0; + if (strstr(lApp->Argv()[1], "proof") == 0) { + dets = + Getline(Form + (" Local Globus Certificates (%s)\n Enter <key>:<new value> to change: ", + details)); + } else { + Warning("GlobusSetCertificate", + "proofserv: cannot prompt for info"); + } + if (dets && dets[0]) { + dets[strlen(dets) - 1] = '\0'; // get rid of \n + det = new char[strlen(dets)]; + strcpy(det, dets); + } else + det = ""; + + if (gDebug > 3) + Info("GlobusSetCertificates", "got det: %s (%d)", det, + strlen(det)); + + } else { + det = ""; + } + + if (strlen(det) > 0) { + + nr = sscanf(det, "%s %s %s %s", tmpvar[0], tmpvar[1], tmpvar[2], + tmpvar[3]); + for (i = 0; i < nr; i++) { + if (!strncmp(tmpvar[i], "cd:", 3) + || !strncmp(tmpvar[i], "Cd:", 3) + || !strncmp(tmpvar[i], "cD:", 3) + || !strncmp(tmpvar[i], "CD:", 3)) { + if (ddir != 0) + SafeDelete(ddir); + ddir = StrDup(tmpvar[i] + 3); + } + if (!strncmp(tmpvar[i], "cf:", 3) + || !strncmp(tmpvar[i], "Cf:", 3) + || !strncmp(tmpvar[i], "cF:", 3) + || !strncmp(tmpvar[i], "CF:", 3)) { + if (dcer != 0) + SafeDelete(dcer); + dcer = StrDup(tmpvar[i] + 3); + } + if (!strncmp(tmpvar[i], "kf:", 3) + || !strncmp(tmpvar[i], "Kf:", 3) + || !strncmp(tmpvar[i], "kF:", 3) + || !strncmp(tmpvar[i], "KF:", 3)) { + if (dkey != 0) + SafeDelete(dkey); + dkey = StrDup(tmpvar[i] + 3); + } + if (!strncmp(tmpvar[i], "ad:", 3) + || !strncmp(tmpvar[i], "Ad:", 3) + || !strncmp(tmpvar[i], "aD:", 3) + || !strncmp(tmpvar[i], "AD:", 3)) { + if (dadi != 0) + SafeDelete(dadi); + dadi = StrDup(tmpvar[i] + 3); + } + } + } + // Build gDetails + temp[0] = '\0'; + sprintf(temp, "%s cd:%s cf:%s kf:%s ad:%s", gPromptReUse, ddir, dcer, + dkey, dadi); + gDetails = temp; + + // Perform "~" expansion ... or allow for paths relative to .globus + if (!strncmp(ddir, "~/", 2)) { + temp[0] = '\0'; + sprintf(temp, "%s%s", userhome, ddir + 1); + if (ddir != 0) + SafeDelete(ddir); + ddir = StrDup(temp); + } else if (strncmp(ddir, "/", 1)) { + temp[0] = '\0'; + sprintf(temp, "%s/%s/%s", userhome, globusdef, ddir); + if (ddir != 0) + SafeDelete(ddir); + ddir = StrDup(temp); + } + if (!strncmp(dcer, "~/", 2)) { + temp[0] = '\0'; + sprintf(temp, "%s%s", userhome, dcer + 1); + if (dcer != 0) + SafeDelete(dcer); + dcer = StrDup(temp); + } else if (strncmp(dcer, "/", 1)) { + temp[0] = '\0'; + sprintf(temp, "%s/%s", ddir, dcer); + if (dcer != 0) + SafeDelete(dcer); + dcer = StrDup(temp); + } + if (!strncmp(dkey, "~/", 2)) { + temp[0] = '\0'; + sprintf(temp, "%s%s", userhome, dkey + 1); + if (dkey != 0) + SafeDelete(dkey); + dkey = StrDup(temp); + } else if (strncmp(dkey, "/", 1)) { + temp[0] = '\0'; + sprintf(temp, "%s/%s", ddir, dkey); + if (dkey != 0) + SafeDelete(dkey); + dkey = StrDup(temp); + } + if (!strncmp(dadi, "~/", 2)) { + temp[0] = '\0'; + sprintf(temp, "%s%s", userhome, dadi + 1); + if (dadi != 0) + SafeDelete(dadi); + dadi = StrDup(temp); + } else if (strncmp(dadi, "/", 1)) { + temp[0] = '\0'; + sprintf(temp, "%s/%s/%s", userhome, globusdef, dadi); + if (dadi != 0) + SafeDelete(dadi); + dadi = StrDup(temp); + } + if (gDebug > 3) + Info("GlobusSetCertificates", "after expansion: %s %s %s", dcer, + dkey, dadi); + + // Save them + setenv("X509_CERT_DIR", dadi, 1); + setenv("X509_USER_CERT", dcer, 1); + setenv("X509_USER_KEY", dkey, 1); + + // Release allocated memory + if (ddir != 0) + SafeDelete(ddir); + if (dcer != 0) + SafeDelete(dcer); + if (dkey != 0) + SafeDelete(dkey); + if (dadi != 0) + SafeDelete(dadi); + + } + + return; +} + +//______________________________________________________________________________ +void GlobusCleanup() +{ + // This function cleans up any stuff related to Globus, releasing + // credentials, security contexts and allocated memory ... + + if (gDebug > 2) + Info("GlobusCleanup:", "cleaning up local Globus stuff ..."); + + if (NumGlbSecCont == 0) { + if (gDebug > 3) + Info("GlobusCleanup:", "Globus never used: nothing to clean"); + return; + } + + int status = 0; + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + + + // Now we can delete the sec context */ + int i; + for (i = 0; i < NumGlbSecCont; i++) { + if ((MajStat = + gss_delete_sec_context(&MinStat, sptrGlbSecCont + i, + GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) { + GlobusError("GlobusCleanup: gss_delete_sec_context", MajStat, + MinStat, 0); + status = 1; + } + } + + // Release memory allocated for security contexts ... + SafeDelete(hostGlbSecCont); + SafeDelete(subjGlbSecCont); + SafeDelete(sptrGlbSecCont); + NumGlbSecCont = 0; + + // Finally check if the shm for imported stuff has not yet been destroyed ... + // Recall the shm_id first ... + TApplication *lApp = gROOT->GetApplication(); + + if (lApp != 0) { + if (strstr(lApp->Argv()[1], "proof") != 0) { + struct shmid_ds shm_ds; + int rc; + // Delegated Credentials + gShmIdCred = (lApp->Argc() > 6) ? atoi(lApp->Argv()[7]) : -1; + if (gShmIdCred != -1) { + if ((rc = shmctl(gShmIdCred, IPC_RMID, &shm_ds)) != 0) { + if ((rc == EINVAL) || (rc == EIDRM)) { + if (gDebug > 3) + Info("GlobusCleanup:", + "credentials shared memory segment already marked as destroyed"); + } else { + Warning("GlobusCleanup:", + "unable to mark segment as destroyed (error: 0x%x)", + rc); + } + } else if (gDebug > 3) + Info("GlobusCleanup:", + "shared memory segment %d marked for destruction", + gShmIdCred); + } else if (gDebug > 3) { + Info("GlobusCleanup:", + "gShmIdCred not defined in this session"); + } + } + } +} diff --git a/globusauth/src/globus_gsi_system_config.c b/globusauth/src/globus_gsi_system_config.c new file mode 100644 index 0000000000000000000000000000000000000000..74f231faf840eba8254a2548f2a5700a76e8644b --- /dev/null +++ b/globusauth/src/globus_gsi_system_config.c @@ -0,0 +1,5391 @@ +#ifndef R__GLBCPATCH +void globus_patch_dummy() +{ +} +#else + +/* This is the corrected version of 'globus_gsi_system_config.c' + * for a correct behaviour of X509_USER_CERT and X509_USER_KEY + * variables in GTK version(s): 2.2.3, 2.2.4, ... + * Version 2.0 should be ok. + */ + +#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL +/** + * @file globus_gsi_sysconfig_system_config.c + * @author Sam Lang, Sam Meder + * + * $RCSfile: globus_gsi_system_config.c,v $ + * $Revision: 1.31 $ + * $Date: 2002/11/15 02:33:59 $ + */ +#endif + +#include "globus_common.h" +#include "globus_gsi_system_config.h" +#include "globus_i_gsi_system_config.h" +#include "globus_gsi_cert_utils.h" +#include <openssl/rand.h> +#include <pwd.h> +#include <time.h> +#include <errno.h> +#include <sys/times.h> +#include "version.h" + +#ifndef DEFAULT_SECURE_TMP_DIR +#ifndef WIN32 +#define DEFAULT_SECURE_TMP_DIR "/tmp" +#else +#define DEFAULT_SECURE_TMP_DIR "c:\\tmp" +#endif +#endif + +#ifndef DEFAULT_EGD_PATH +#ifndef WIN32 +#define DEFAULT_EGD_PATH "/tmp" +#else +#define DEFAULT_EGD_PATH "c:\\tmp" +#endif +#endif + +#ifndef DEFAULT_RANDOM_FILE +#ifndef WIN32 +#define DEFAULT_RANDOM_FILE "/tmp" +#else +#define DEFAULT_RANDOM_FILE UNDEFINED_VALUE +#endif +#endif + +#ifdef WIN32 +#include "winglue.h" +#include <io.h> +#else +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <dirent.h> +#endif + +#define X509_CERT_DIR "X509_CERT_DIR" +#define X509_CERT_FILE "X509_CERT_FILE" +#define X509_USER_PROXY "X509_USER_PROXY" +#define X509_USER_CERT "X509_USER_CERT" +#define X509_USER_KEY "X509_USER_KEY" +#define X509_UNIQUE_PROXY_FILE "x509up_p" +#define X509_USER_PROXY_FILE "x509up_u" +#define SIGNING_POLICY_FILE_EXTENSION ".signing_policy" + +/* This is added after the CA name hash to make the policy filename */ +#define SIGNING_POLICY_FILE_EXTENSION ".signing_policy" + +#ifdef WIN32 +#define FILE_SEPERATOR "\\" +#define GSI_REGISTRY_DIR "software\\Globus\\GSI" +#define X509_DEFAULT_USER_CERT ".globus\\usercert.pem" +#define X509_DEFAULT_USER_KEY ".globus\\userkey.pem" +#define X509_DEFAULT_PKCS12_FILE ".globus\\usercred.p12" +#define X509_DEFAULT_TRUSTED_CERT_DIR "SLANG: NEEDS TO BE DETERMINED" +#define X509_INSTALLED_TRUSTED_CERT_DIR "SLANG: NEEDS TO BE DETERMINED" +#define X509_LOCAL_TRUSTED_CERT_DIR ".globus\\certificates" +#define X509_DEFAULT_CERT_DIR "SLANG: NEEDS TO BE DETERMINED" +#define X509_INSTALLED_CERT_DIR "etc" +#define X509_LOCAL_CERT_DIR ".globus" +#define DEFAULT_GRIDMAP "SLANG: NEEDS TO BE DETERMINED" +#define LOCAL_GRIDMAP "SLANG: NEEDS TO BE DETERMINED" +#else +#define FILE_SEPERATOR "/" +#define X509_DEFAULT_USER_CERT ".globus/usercert.pem" +#define X509_DEFAULT_USER_KEY ".globus/userkey.pem" +#define X509_DEFAULT_PKCS12_FILE ".globus/usercred.p12" +#define X509_DEFAULT_TRUSTED_CERT_DIR "/etc/grid-security/certificates" +#define X509_INSTALLED_TRUSTED_CERT_DIR "share/certificates" +#define X509_LOCAL_TRUSTED_CERT_DIR ".globus/certificates" +#define X509_DEFAULT_CERT_DIR "/etc/grid-security" +#define X509_INSTALLED_CERT_DIR "etc" +#define X509_LOCAL_CERT_DIR ".globus" +#define DEFAULT_GRIDMAP "/etc/grid-security/grid-mapfile" +#define INSTALLED_GRIDMAP "etc/grid-mapfile" +#define LOCAL_GRIDMAP ".gridmap" +#endif + +#define X509_HOST_PREFIX "host" +#define X509_CERT_SUFFIX "cert.pem" +#define X509_KEY_SUFFIX "key.pem" + +#define X509_HASH_LENGTH 8 + +#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL + +#define GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR \ + globus_error_put(globus_error_wrap_errno_error( \ + GLOBUS_GSI_SYSCONFIG_MODULE, \ + errno, \ + GLOBUS_GSI_SYSCONFIG_ERROR_ERRNO, \ + "%s:%d: Could not allocate enough memory", \ + __FILE__, __LINE__)) + + +int globus_i_gsi_sysconfig_debug_level; +FILE * globus_i_gsi_sysconfig_debug_fstream; + +static int globus_l_gsi_sysconfig_activate(void); +static int globus_l_gsi_sysconfig_deactivate(void); + +int globus_i_gsi_sysconfig_debug_level = 0; + +/** + * Module descriptor static initializer. + */ +globus_module_descriptor_t globus_i_gsi_sysconfig_module = +{ + "globus_sysconfig", + globus_l_gsi_sysconfig_activate, + globus_l_gsi_sysconfig_deactivate, + GLOBUS_NULL, + GLOBUS_NULL, + &local_version +}; + +/** + * Module activation + */ +static +int +globus_l_gsi_sysconfig_activate(void) +{ + int result = (int) GLOBUS_SUCCESS; + const char * random_file = NULL; + char * egd_path = NULL; + clock_t uptime; + struct tms proc_times; + char buffer[200]; + char * tmp_string; + static char * _function_name_ = + "globus_l_gsi_sysconfig_activate"; + + tmp_string = getenv("GLOBUS_GSI_SYSCONFIG_DEBUG_LEVEL"); + if (tmp_string != GLOBUS_NULL) + { + globus_i_gsi_sysconfig_debug_level = atoi(tmp_string); + + if ( globus_i_gsi_sysconfig_debug_level < 0) + { + globus_i_gsi_sysconfig_debug_level = 0; + } + } + + tmp_string = getenv("GLOBUS_GSI_SYSCONFIG_DEBUG_FILE"); + if (tmp_string != GLOBUS_NULL) + { + globus_i_gsi_sysconfig_debug_fstream = fopen(tmp_string, "w"); + if (globus_i_gsi_sysconfig_debug_fstream == NULL) + { + result = (int) GLOBUS_FAILURE; + goto exit; + } + } + else + { + /* if the env. var. isn't set, use stderr */ + globus_i_gsi_sysconfig_debug_fstream = stderr; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + globus_module_activate(GLOBUS_GSI_CERT_UTILS_MODULE); + + /* OpenSSL's random generator is fed with random + * information, which requires system dependant information + * (path names) + */ + + random_file = RAND_file_name(buffer, 200); + if (random_file) + { + RAND_load_file(random_file, 1024L * 1024L); + } + + egd_path = getenv("EGD_PATH"); + if (egd_path == NULL) + { + egd_path = DEFAULT_EGD_PATH; + } + RAND_egd(egd_path); + + if (RAND_status() == 0) + { + globus_gsi_statcheck_t status; + + /* this function does a RAND_add based on the + * filename - provides platform independence + */ + GLOBUS_GSI_SYSCONFIG_FILE_EXISTS(DEFAULT_RANDOM_FILE, &status); + + /* probably overestimating the entropy in the below */ + + uptime = times(&proc_times); + + RAND_add((void *) &uptime, sizeof(clock_t), 2); + RAND_add((void *) &proc_times, sizeof(struct tms), 8); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (globus_i_gsi_sysconfig_debug_fstream, + "RAND_status = %d", RAND_status())); + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + exit: + return result; +} + +/** + * Module deactivation + * + */ +static +int +globus_l_gsi_sysconfig_deactivate(void) +{ + int result = (int) GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_l_gsi_sysconfig_deactivate"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + RAND_cleanup(); + globus_module_deactivate(GLOBUS_GSI_CERT_UTILS_MODULE); + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + if (globus_i_gsi_sysconfig_debug_fstream != stderr) + { + fclose(globus_i_gsi_sysconfig_debug_fstream); + } + + return result; +} +/* globus_l_gsi_proxy_deactivate() */ + + +globus_result_t +globus_i_gsi_sysconfig_create_cert_dir_string( + char ** cert_dir, + char ** cert_dir_value, + globus_gsi_statcheck_t * status, + const char * format, + ...) +{ + va_list ap; + globus_result_t result; + + static char * _function_name_ = + "globus_i_gsi_sysconfig_create_cert_dir_string"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *cert_dir = NULL; + + va_start(ap, format); + + *cert_dir_value = globus_gsi_cert_utils_v_create_string(format, ap); + + va_end(ap); + + if (*cert_dir_value == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + result = GLOBUS_GSI_SYSCONFIG_FILE_EXISTS(*cert_dir_value, status); + if (result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto exit; + } + + if (format && *status == GLOBUS_FILE_DIR) + { + *cert_dir = *cert_dir_value; + } + else if ((*status) != GLOBUS_FILE_DOES_NOT_EXIST) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR, + ("%s %s\n", + *cert_dir_value, + globus_l_gsi_sysconfig_status_strings[*status])); + goto exit; + } + + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + + +globus_result_t +globus_i_gsi_sysconfig_create_cert_string( + char ** cert_string, + char ** cert_string_value, + globus_gsi_statcheck_t * status, + const char * format, + ...) +{ + va_list ap; + globus_result_t result; + + static char * _function_name_ = + "globus_i_gsi_sysconfig_create_cert_string"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *cert_string = NULL; + + va_start(ap, format); + + *cert_string_value = globus_gsi_cert_utils_v_create_string(format, ap); + + va_end(ap); + + if (*cert_string_value == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + result = GLOBUS_GSI_SYSCONFIG_CHECK_CERTFILE(*cert_string_value, status); + if (result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto exit; + } + + if (format && (*status) == GLOBUS_FILE_VALID) + { + *cert_string = *cert_string_value; + } + else if ((*status) != GLOBUS_FILE_DOES_NOT_EXIST) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + ("%s %s\n", + *cert_string_value, + globus_l_gsi_sysconfig_status_strings[*status])); + goto exit; + } + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + +globus_result_t +globus_i_gsi_sysconfig_create_key_string( + char ** key_string, + char ** key_string_value, + globus_gsi_statcheck_t * status, + const char * format, + ...) +{ + va_list ap; + globus_result_t result; + + static char * _function_name_ = + "globus_i_gsi_sysconfig_create_key_string"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *key_string = NULL; + + va_start(ap, format); + + *key_string_value = globus_gsi_cert_utils_v_create_string(format, ap); + + va_end(ap); + + if (*key_string_value == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + result = GLOBUS_GSI_SYSCONFIG_CHECK_KEYFILE(*key_string_value, status); + if (result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto exit; + } + + if (format && (*status) == GLOBUS_FILE_VALID) + { + *key_string = *key_string_value; + } + else if ((*status) != GLOBUS_FILE_DOES_NOT_EXIST) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("%s %s\n", + *key_string_value, + globus_l_gsi_sysconfig_status_strings[*status])); + goto exit; + } + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + +#endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */ + +#ifdef WIN32 /* define all the *_win32 functions */ + +#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL + + +/** + * WIN32 - Set Key Permissions + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Set the file permissions of a file to read only by the user + * which are the permissions that should be set for all private keys. + * + * @param filename + * + * @return + * GLOBUS_SUCCESS or an error object id + */ +globus_result_t +globus_gsi_sysconfig_set_key_permissions_win32( + char * filename) +{ + globus_result_t result = GLOBUS_SUCCESS; + globus_gsi_statcheck_t status; + static char * _function_name_ = + "globus_gsi_sysconfig_set_key_permissions_win32"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + result = globus_gsi_sysconfig_file_exists_win32( + filename, + &status); + if (result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_SETTING_PERMS); + goto exit; + } + + if (status != GLOBUS_FILE_VALID || + status != GLOBUS_FILE_DIR) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GIS_SYSCONFIG_ERROR_SETTING_PERMS, + ("Invalid file: %s", filename)); + goto exit; + } + +#error need to fill this in + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * WIN32 - Get HOME Directory + * @ingroup globus_i_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the HOME directory, currently c:\windows + * + * @param home_dir + * The home directory of the current user + * @return + * GLOBUS_SUCCESS if no error occured, otherwise + * an error object is returned. + */ +globus_result_t +globus_i_gsi_sysconfig_get_home_dir_win32( + char ** home_dir) +{ + globus_result_t result; + + const char * _function_name_ = + "globus_i_gsi_sysconfig_get_home_dir_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *home_dir = "c:\\windows"; + + if ((*home_dir) == NULL) + { + result = GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_HOME_DIR, + ("Could not get a home directory for this machine")); + goto error_exit; + } + + result = GLOBUS_SUCCESS; + + error_exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * WIN32 - File Exists + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Check that the file exists + * + * @param filename the file to check + * @param status the status of the file + * + * @return + * GLOBUS_SUCCESS (even if the file doesn't exist) - in some + * abortive cases an error object identifier is returned + */ +globus_result_t +globus_gsi_sysconfig_file_exists_win32( + const char * filename, + globus_gsi_statcheck_t * status) +{ + globus_result_t result; + struct stat stx; + + static char * _function_name_ = + "globus_i_gsi_sysconfig_file_exists_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if (stat(filename,&stx) == -1) + { + switch (errno) + { + case ENOENT: + case ENOTDIR: + *status = GLOBUS_DOES_NOT_EXIST; + result = GLOBUS_SUCCESS; + goto exit; + + case EACCES: + + *status = GLOBUS_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + + default: + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_ERRNO, + __FILE__":%d:%s: Error getting status of keyfile\n", + __LINE__, + _function_name_)); + goto exit; + } + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx, sizeof(stx), 2); + + if (stx.st_size == 0) + { + *status = GLOBUS_ZERO_LENGTH; + result = GLOBUS_SUCCESS; + goto exit; + } + + *status = GLOBUS_VALID; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + + +/** + * WIN32 - Check File Status for Key + * @ingroup globus_i_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * This is a convenience function used to check the status of a + * private key file. The desired status is only the current user has + * ownership and read permissions, everyone else should not be able + * to access it. + * + * @param filename + * The name of the file to check the status of + * @param status + * The status of the file being checked + * see @ref globus_gsi_statcheck_t for possible values + * of this variable + * + * @return + * GLOBUS_SUCCESS if the status of the file was able + * to be determined. Otherwise, an error object + * identifier + * + * @see globus_gsi_statcheck_t + */ +globus_result_t +globus_i_gsi_sysconfig_check_keyfile_win32( + const char * filename, + globus_gsi_statcheck_t * status) +{ + struct stat stx; + globus_result_t result; + static char * _function_name_ = + "globus_i_gsi_sysconfig_check_keyfile_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if (stat(filename,&stx) == -1) + { + switch (errno) + { + case ENOENT: + case ENOTDIR: + *status = GLOBUS_DOES_NOT_EXIST; + result = GLOBUS_SUCCESS; + goto exit; + + case EACCES: + + *status = GLOBUS_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + + default: + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + __FILE__":%d:%s: Error getting status of keyfile\n", + __LINE__, + _function_name_)); + goto exit; + } + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx,sizeof(stx),2); + + if (stx.st_size == 0) + { + *status = GLOBUS_ZERO_LENGTH; + result = GLOBUS_SUCCESS; + } + + *status = GLOBUS_VALID; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * WIN32 - Check File Status for Cert + * @ingroup globus_i_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * This is a convenience function used to check the status of a + * certificate file. The desired status is the current user has + * ownership and read/write permissions, while group and others only + * have read permissions. + * + * @param filename + * The name of the file to check the status of + * @param status + * The status of the file being checked + * see @ref globus_gsi_statcheck_t for possible values + * of this variable + * + * @return + * GLOBUS_SUCCESS if the status of the file was able + * to be determined. Otherwise, an error object + * identifier + * + * @see globus_gsi_statcheck_t + */ +globus_result_t +globus_i_gsi_sysconfig_check_certfile_win32( + const char * filename, + globus_gsi_statcheck_t * status) +{ + globus_result_t result; + struct stat stx; + + static char * _function_name_ = + "globus_i_gsi_sysconfig_check_certfile_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if (stat(filename,&stx) == -1) + { + switch (errno) + { + case ENOENT: + case ENOTDIR: + *status = GLOBUS_DOES_NOT_EXIST; + result = GLOBUS_SUCCESS; + goto exit; + + case EACCES: + + *status = GLOBUS_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + + default: + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + __FILE__":%d:%s: Error getting status of keyfile\n", + __LINE__, + _function_name_)); + goto exit; + } + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx,sizeof(stx),2); + + if (stx.st_size == 0) + { + *status = GLOBUS_ZERO_LENGTH; + result = GLOBUS_SUCCESS; + } + + *status = GLOBUS_VALID; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * @name WIN32 - Get Current Working Directory + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the current working directory on a windows system + * + * @param working_dir + * The working directory to get + * @return + * GLOBUS_SUCCESS if no error occurred, otherwise an error object + * ID is returned + */ +globus_result_t +globus_gsi_sysconfig_get_current_working_dir_win32( + char ** working_dir) +{ + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_get_current_working_dir_win32"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error /* this needs to be filled in */ + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * @name WIN32 - Make Absolute Path + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Make the filename into an absolute path string based + * on the current working directory. + * + * @param filename + * the filename to get the absolute path of. + * @param absolute_path + * The resulting absolute path + * @return + * GLOBUS_SUCCESS if no error occurred, otherwise + * an error object ID is returned + */ +globus_result_t +globus_gsi_sysconfig_make_absolute_path_for_filename_win32( + char * filename, + char ** absolute_path) +{ + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_make_absolute_path_for_filename_win32"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error /* this needs to be filled in */ + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * @name WIN32 - Split Directory and Filename + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Split the directory and filename portions of a filename string + * into two separate strings + * + * @param full_filename + * @param dir_string + * @param filename_string + * + * @return + */ +globus_result_t +globus_gsi_sysconfig_split_dir_and_filename_win32( + char * full_filename, + char ** dir_string, + char ** filename_string) +{ + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_split_dir_and_filename_win32"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error /* this needs to be filled in */ + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * WIN32 - Get User ID + * @ingroup globus_i_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get a unique string representing the current user. + * On Windows, SLANG: NOT DETERMINED + */ +globus_result_t +globus_gsi_sysconfig_get_user_id_string_win32( + char ** user_id_string) +{ + int uid; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_user_id_string_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + result = globus_gsi_sysconfig_get_username_win32(user_id_string); + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return GLOBUS_SUCCESS; +} +/* @} */ + +/** + * WIN32 - Get Username + * @ingroup globus_i_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the username of the current user. + * On Windows, SLANG: NOT DETERMINED + */ +globus_result_t +globus_gsi_sysconfig_get_username_win32( + char ** username) +{ + static char * _function_name_ = + "globus_gsi_sysconfig_get_username_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error /* SLANG: need to set the string to the username or whatever */ + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return GLOBUS_SUCCESS; +} +/* @} */ + +/** + * WIN32 - Get Process ID + * @ingroup globus_i_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get a unique string representing the current process. + * On Windows, SLANG: NOT DETERMINED + */ +globus_result_t +globus_gsi_sysconfig_get_proc_id_string_win32( + char ** proc_id_string) +{ + int uid; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_proc_id_string_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error /* SLANG: need to set the string to the process name or whatever */ + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return GLOBUS_SUCCESS; +} +/* @} */ + +#endif + +/** + * WIN32 - Get Trusted CA Cert Dir + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the Trusted Certificate Directory containing the trusted + * Certificate Authority certificates. This directory is determined + * in the order shown below. Failure in one method results in attempting + * the next. + * + * <ol> + * <li> <b>X509_CERT_DIR environment variable</b> - if this is set, the + * trusted certificates will be searched for in that directory. This + * variable allows the end user to specify the location of trusted + * certificates. + * <li> <b>"x509_cert_dir" registry key</b> - If + * this registry key is set on windows, the directory it points to should + * contain the trusted certificates. The path to the registry key is + * software\Globus\GSI + * <li> <b>\<user home directory\>\.globus\certificates</b> - If this + * directory exists, and the previous methods of determining the trusted + * certs directory failed, this directory will be used. + * <li> <b>Host Trusted Cert Dir</b> - This location is intended + * to be independant of the globus installation ($GLOBUS_LOCATION), and + * is generally only writeable by the host system administrator. + * SLANG: This value is not currently set for WINDOWS + * <li> <b>Globus Install Trusted Cert Dir</b> - this + * is $GLOBUS_LOCATION\share\certificates. + * </ol> + * + * @param cert_dir + * The trusted certificates directory + * @return + * GLOBUS_SUCCESS if no error occurred, and a sufficient trusted + * certificates directory was found. Otherwise, an error object + * identifier returned. + */ +globus_result_t +globus_gsi_sysconfig_get_cert_dir_win32( + char ** cert_dir) +{ + char * env_cert_dir = NULL; + char * val_cert_dir[512]; + char * reg_cert_dir = NULL; + char * local_cert_dir = NULL; + char * default_cert_dir = NULL; + char * installed_cert_dir = NULL; + int len; + HKEY hkDir = NULL; + globus_result_t result; + char * home; + char * globus_location; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_cert_dir_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *cert_dir = NULL; + + if (getenv(X509_CERT_DIR)) + { + result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & env_cert_dir, + getenv(X509_CERT_DIR)); + if (result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto error_exit; + } + } + + if (!(*cert_dir)) + { + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); + lval = sizeof(val_cert_dir)-1; + if (hkDir && (RegQueryValueEx(hkDir,"x509_cert_dir",0,&type, + val_cert_dir,&lval) == ERROR_SUCCESS)) + { + if((result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & reg_cert_dir, + val_cert_dir)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + RegCloseKey(hkDir); + } + + /* now check for a trusted CA directory in the user's home directory */ + if(!(*cert_dir)) + { + if((result = globus_i_gsi_sysconfig_get_home_dir(&home)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + + if (home) + { + if((result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & local_cert_dir, + "%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_TRUSTED_CERT_DIR)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + + /* now look in $GLOBUS_LOCATION/share/certificates */ + if (!(*cert_dir)) + { + if((result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & installed_cert_dir, + X509_INSTALLED_TRUSTED_CERT_DIR)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + + /* now check for host based default directory */ + if (!(*cert_dir)) + { + globus_location = getenv("GLOBUS_LOCATION"); + + if (globus_location) + { + if((result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & default_cert_dir, + "%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_DEFAULT_TRUSTED_CERT_DIR)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 1, (stderr, "Using cert_dir = %s\n", + (*cert_dir ? *cert_dir : "null"))); + + if(!(*cert_dir)) + { + result = globus_error_put(globus_error_construct_string( + GLOBUS_GSI_SYSCONFIG_MODULE, + NULL, + "The trusted certificates directory could not be" + "found in any of the following locations: \n" + "1) env. var. X509_CERT_DIR=%s\n" + "2) registry key x509_cert_dir: %s\n" + "3) %s\n4) %s\n5) %s\n", + env_cert_dir, + reg_cert_dir, + local_cert_dir, + installed_cert_dir, + default_cert_dir)); + + goto error_exit; + } + + result = GLOBUS_SUCCESS; + goto done: + + error_exit: + + if(*cert_dir) + { + globus_libc_free(*cert_dir); + *cert_dir = NULL; + } + + done: + + if(env_cert_dir && (env_cert_dir != (*cert_dir))) + { + globus_libc_free(env_cert_dir); + } + if(reg_cert_dir && (reg_cert_dir != (*cert_dir))) + { + globus_libc_free(reg_cert_dir); + } + if(local_cert_dir && (local_cert_dir != (*cert_dir))) + { + globus_libc_free(local_cert_dir); + } + if(installed_cert_dir && (installed_cert_dir != (*cert_dir))) + { + globus_libc_free(installed_cert_dir); + } + if(default_cert_dir && (default_cert_dir != (*cert_dir))) + { + globus_libc_free(default_cert_dir); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * WIN32 - Get User Certificate Filename + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the User Certificate Filename based on the current user's + * environment. The following locations are searched for cert and key + * files in order: + * + * <ol> + * <li>environment variables X509_USER_CERT and X509_USER_KEY + * <li>registry keys x509_user_cert and x509_user_key in software\Globus\GSI + * <li><users home directory>\.globus\usercert.pem and + * <users home directory>\.globus\userkey.pem + * <li><users home directory\.globus\usercred.p12 - this is a PKCS12 credential + * </ol> + * + * @param user_cert + * pointer the filename of the user certificate + * @param user_key + * pointer to the filename of the user key + * @return + * GLOBUS_SUCCESS if the cert and key files were found in one + * of the possible locations, otherwise an error object identifier + * is returned + */ +globus_result_t +globus_gsi_sysconfig_get_user_cert_filename_win32( + char ** user_cert, + char ** user_key) +{ + int len; + char * home = NULL; + char * env_user_cert = NULL; + char * env_user_key = NULL; + char * reg_user_cert = NULL; + char * reg_user_key = NULL; + char * default_user_cert = NULL; + char * default_user_key = NULL; + char * default_pkcs12_user_cred = NULL; + globus_result_t result; + HKEY hkDir = NULL; + char val_user_cert[512]; + char val_user_key[512]; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_user_cert_filename_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *user_cert = NULL; + *user_key = NULL; + + /* first, check environment variables for valid filenames */ + + if(getenv(X509_USER_CERT)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + user_cert, + &env_user_cert, + getenv(X509_USER_CERT)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto error_exit; + } + } + + if(getenv(X509_USER_KEY)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + user_key, + &env_user_key, + getenv(X509_USER_KEY)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTIN_KEY_STRING); + goto error_exit; + } + } + + /* next, check windows registry keys for valid filenames */ + + if(!(*user_cert) || !(*user_key)) + { + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); + lval = sizeof(val_user_cert)-1; + if (hkDir && (RegQueryValueEx( + hkDir, + "x509_user_cert", + 0, + &type, + val_user_cert,&lval) == ERROR_SUCCESS)) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + user_cert, + & reg_user_cert, + val_user_cert)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + user_key, + & reg_user_key, + val_user_key)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + RegCloseKey(hkDir); + } + + + /* next, check default locations */ + if(!(*user_cert) || !(*user_key)) + { + result = GLOBUS_I_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result == GLOBUS_SUCCESS && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_cert_string( + user_cert, + & default_user_cert, + "%s%s%s", + home, + DEFEAULT_SEPERATOR, + X509_DEFAULT_USER_CERT); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_WITH_USER_CERT_FILENAME); + goto error_exit; + } + + result = globus_i_gsi_sysconfig_create_key_string( + key_cert, + & default_key_cert, + "%s%s%s", + home, + DEFAULT_SEPERATOR, + X509_DEFAULT_USER_KEY); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_WITH_USER_KEY_FILENAME); + goto error_exit; + } + } + } + + /* if the cert & key don't exist in the default locations + * or those specified by the environment variables, a + * pkcs12 cert will be searched for + */ + if(!(*user_cert) || !(*user_key)) + { + if((result = globus_i_gsi_sysconfig_get_home_dir(&home)) == GLOBUS_SUCCESS) + { + if((result = globus_i_gsi_sysconfig_create_key_string( + user_key, + & default_pkcs12_user_cred, + "%s%s%s", + home, + FILE_SEPERATOR, + X509_DEFAULT_PKCS12_FILE)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + *user_cert = *user_key; + } + } + + if(!(*user_cert) || !(*user_key)) + { + result = GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_FILENAME, + ("The user cert could not be found in: \n" + "1) env. var. X509_USER_CERT=%s\n" + "2) registry key x509_user_cert: %s\n" + "3) %s\n4) %s\n\n" + "The user key could not be found in:\n," + "1) env. var. X509_USER_KEY=%s\n" + "2) registry key x509_user_key: %s\n" + "3) %s\n4) %s\n", + env_user_cert, + reg_user_cert, + default_user_cert, + default_pkcs12_user_cred, + env_user_key, + reg_user_key, + default_user_key, + default_pkcs12_user_cred)); + + goto error_exit; + } + +#ifdef DEBUG + fprintf(stderr,"Using x509_user_cert=%s\n x509_user_key =%s\n", + (*user_cert) ? (*user_cert) : NULL, + (*user_key) ? (*user_key) : NULL); +#endif + + result = GLOBUS_SUCCESS; + goto done; + + error_exit: + + if(*user_cert) + { + globus_libc_free(*user_cert); + *user_cert = NULL; + } + if(*user_key) + { + globus_libc_free(*user_key); + *user_key = NULL; + } + + done: + + if(env_user_cert && env_user_cert != (*user_cert)) + { + globus_libc_free(env_user_cert); + } + if(env_user_key && env_user_key != (*user_key)) + { + globus_libc_free(env_user_key); + } + if(default_user_cert && default_user_cert != (*user_cert)) + { + globus_libc_free(default_user_cert); + } + if(default_user_key && default_user_key != (*user_key)) + { + globus_libc_free(default_user_key); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * WIN32 - Get Host Certificate and Key Filenames + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the Host Certificate and Key Filenames based on the current user's + * environment. The host cert and key are searched for in the following + * locations (in order): + * + * <ol> + * <li>X509_USER_CERT and X509_USER_KEY environment variables + * <li>registry keys x509_user_cert and x509_user_key in software\Globus\GSI + * <li>SLANG: NOT DETERMINED - this is the default location + * <li><GLOBUS_LOCATION>\etc\host[cert|key].pem + * <li><users home directory>\.globus\host[cert|key].pem + * </ol> + * + * @param host_cert + * pointer to the host certificate filename + * @param host_key + * pointer to the host key filename + * + * @return + * GLOBUS_SUCCESS if the host cert and key were found, otherwise + * an error object identifier is returned + */ +globus_result_t +globus_gsi_sysconfig_get_host_cert_filename_win32( + char ** host_cert, + char ** host_key) +{ + int len; + char * home = NULL; + char * host_cert = NULL; + char * host_key = NULL; + char * env_host_cert = NULL; + char * env_host_key = NULL; + char * reg_host_cert = NULL; + char * reg_host_key = NULL; + char * default_host_cert = NULL; + char * default_host_key = NULL; + char * installed_host_cert = NULL; + char * installed_host_key = NULL; + char * local_host_cert = NULL; + char * local_host_key = NULL; + globus_result_t result; + + HKEY hkDir = NULL; + char val_host_cert[512]; + char val_host_key[512]; + + static char * _function_name_ = + "globus_gsi_sysconfig_host_cert_filename_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *host_cert = NULL; + *host_key = NULL; + + /* first check environment variables for valid filenames */ + + if(getenv(X509_USER_CERT)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & env_host_cert, + getenv(X509_USER_CERT)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto error_exit; + } + } + + if(getenv(X509_USER_KEY)) + { + result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & env_host_key, + getenv(X509_USER_KEY)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto error_exit; + } + } + + /* now check the windows registry for valid filenames */ + if(!(*host_cert) || !(*host_key)) + { + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); + lval = sizeof(val_host_cert)-1; + if (hkDir && (RegQueryValueEx(hkDir, + "x509_user_cert", + 0, + &type, + val_host_cert, + &lval) == ERROR_SUCCESS)) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & reg_host_cert, + val_host_cert)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_cert_string( + host_key, + & reg_host_key, + val_host_key)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + RegCloseKey(hkDir); + } + + /* now check default locations for valid filenames */ + if(!(*host_cert) || !(*host_key)) + { + if((result = globus_i_gsi_sysconfig_get_home_dir(&home)) == GLOBUS_SUCCESS) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & default_host_cert, + "%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & default_key_cert, + "%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + + /* now check intstalled location for host cert */ + if(!(*host_cert) || !(*host_key)) + { + globus_location = getenv("GLOBUS_LOCATION"); + + if(globus_location) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & installed_host_cert, + "%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & installed_host_key, + "%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + + if(!(*host_cert) || !(*host_key)) + { + if(GLOBUS_I_GSI_SYSCONFIG_GET_HOME_DIR(&home) == GLOBUS_SUCCESS) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & local_host_cert, + "%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & local_key_cert, + "%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + +#ifdef DEBUG + fprintf(stderr,"Using x509_user_cert=%s\n x509_user_key =%s\n", + host_cert, host_key); +#endif + + if(!(*host_cert) || !(*host_key)) + { + result = GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_FILENAME, + ("The user cert could not be found in: \n" + "1) env. var. X509_USER_CERT=%s\n" + "2) registry key x509_user_cert: %s\n" + "3) %s\n4) %s5) %s\n\n" + "The user key could not be found in:\n," + "1) env. var. X509_USER_KEY=%s\n" + "2) registry key x509_user_key: %s\n" + "3) %s\n4) %s5) %s\n", + env_host_cert, + reg_host_cert, + default_host_cert, + installed_host_cert, + local_host_cert, + env_host_key, + reg_host_key, + default_host_key, + installed_host_key, + local_host_key)); + + goto error_exit; + } + + result = GLOBUS_SUCCESS; + goto done; + + error_exit: + + if(*host_cert) + { + globus_libc_free(*host_cert); + *host_cert = NULL; + } + if(*host_key) + { + globus_libc_free(*host_key); + *host_key = NULL; + } + + done: + + if(env_host_cert && env_host_cert != *host_cert) + { + globus_libc_free(env_host_cert); + } + if(env_host_key && env_host_key != *host_key) + { + globus_libc_free(env_host_key); + } + if(reg_host_cert && reg_host_cert != *host_cert) + { + globus_libc_free(reg_host_cert); + } + if(reg_host_key && reg_host_key != *host_key) + { + globus_libc_free(reg_host_key); + } + if(installed_host_cert && installed_host_cert != *host_cert) + { + globus_libc_free(installed_host_cert); + } + if(installed_host_key && installed_host_key != *host_key) + { + globus_libc_free(installed_host_key); + } + if(local_host_cert && local_host_cert != *host_cert) + { + globus_libc_free(local_host_cert); + } + if(local_host_key && local_host_key != *host_key) + { + globus_libc_free(local_host_key); + } + if(default_host_cert && default_host_cert != host_cert) + { + globus_libc_free(default_host_cert); + } + if(default_host_key && default_host_key != host_key) + { + globus_libc_free(default_host_key); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * WIN32 - Get Service Certificate and Key Filenames + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the Service Certificate Filename based on the current user's + * environment. The host cert and key are searched for in the following + * locations (in order): + * + * <ol> + * <li>X509_USER_CERT and X509_USER_KEY environment variables + * <li>registry keys x509_user_cert and x509_user_key in software\Globus\GSI + * <li>SLANG: NOT DETERMINED - this is the default location + * <li>GLOBUS_LOCATION\etc\{service_name}\{service_name}[cert|key].pem + * So for example, if my service was named: myservice, the location + * of the certificate would be: + * GLOBUS_LOCATION\etc\myservice\myservicecert.pem + * <li><users home>\.globus\{service_name}\{service_name}[cert|key].pem + * </ol> + * + * @param service_name + * The name of the service which allows us to determine the + * locations of cert and key files to look for + * @param service_cert + * pointer to the host certificate filename + * @param service_key + * pointer to the host key filename + * + * @return + * GLOBUS_SUCCESS if the service cert and key were found, otherwise + * an error object identifier + */ +globus_result_t +globus_gsi_sysconfig_get_service_cert_filename_win32( + char * service_name, + char ** service_cert_filename, + char ** service_key_filename) +{ + int len; + char * home = NULL; + char * service_cert = NULL; + char * service_key = NULL; + char * env_service_cert = NULL; + char * env_service_key = NULL; + char * reg_service_cert = NULL; + char * reg_service_key = NULL; + char * default_service_cert = NULL; + char * default_service_key = NULL; + char * installed_service_cert = NULL; + char * installed_service_key = NULL; + char * local_service_cert = NULL; + char * local_service_key = NULL; + globus_result_t result; + + HKEY hkDir = NULL; + char val_service_cert[512]; + char val_service_key[512]; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_service_cert_filename_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *service_cert = NULL; + *service_key = NULL; + + /* first check environment variables for valid filenames */ + + if(getenv(X509_USER_CERT)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + &env_service_cert, + getenv(X509_USER_CERT)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto error_exit; + } + } + + if(getenv(X509_USER_KEY)) + { + result = globus_i_gsi_sysconfig_create_key_string( + service_key, + &env_service_key, + getenv(X509_USER_KEY)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto error_exit; + } + } + + /* now check the windows registry for valid filenames */ + if(!(*service_cert) || !(*service_key)) + { + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); + lval = sizeof(val_service_cert)-1; + if (hkDir && (RegQueryValueEx(hkDir, + "x509_user_cert", + 0, + &type, + val_service_cert, + &lval) == ERROR_SUCCESS)) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & reg_service_cert, + val_service_cert)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_cert_string( + service_key, + & reg_service_key, + val_service_key)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + RegCloseKey(hkDir); + } + + + /* now check default locations for valid filenames */ + if(!(*service_cert) || !(*service_key)) + { + if((result = globus_i_gsi_sysconfig_get_home_dir(&home)) == GLOBUS_SUCCESS) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & default_service_cert, + "%s%s%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_CERT_SUFFIX)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & default_key_cert, + "%s%s%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_KEY_SUFFIX)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + + /* now check intstalled location for service cert */ + if(!(*service_cert) || !(*service_key)) + { + globus_location = getenv("GLOBUS_LOCATION"); + + if(globus_location) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & installed_service_cert, + "%s%s%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_CERT_SUFFIX)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & installed_service_key, + "%s%s%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_KEY_SUFFIX)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + + if(!(*service_cert) || !(*service_key)) + { + if (home) { + free(home); + home = NULL; + } + if(GLOBUS_I_GSI_SYSCONFIG_GET_HOME_DIR(&home) == GLOBUS_SUCCESS) + { + if((result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & local_service_cert, + "%s%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_CERT_SUFFIX)) != GLOBUS_SUCCESS || + (result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & local_key_cert, + "%s%s%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_KEY_SUFFIX)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + } + +#ifdef DEBUG + fprintf(stderr,"Using x509_user_cert=%s\n x509_user_key =%s\n", + service_cert, service_key); +#endif + + if(!(*service_cert) || !(*service_key)) + { + result = GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_FILENAME, + ("The user cert could not be found in: \n" + "1) env. var. X509_USER_CERT=%s\n" + "2) registry key x509_user_cert: %s\n" + "3) %s\n4) %s5) %s\n\n" + "The user key could not be found in:\n," + "1) env. var. X509_USER_KEY=%s\n" + "2) registry key x509_user_key: %s\n" + "3) %s\n4) %s5) %s\n", + env_service_cert, + reg_service_cert, + default_service_cert, + installed_service_cert, + local_service_cert, + env_service_key, + reg_service_key, + default_service_key, + installed_service_key, + local_service_key)); + + goto error_exit; + } + + result = GLOBUS_SUCCESS; + goto done; + + error_exit: + + if(*service_cert) + { + globus_libc_free(*service_cert); + *service_cert = NULL; + } + if(*service_key) + { + globus_libc_free(*service_key); + *service_key = NULL; + } + + done: + + if(env_service_cert && env_service_cert != *service_cert) + { + globus_libc_free(env_service_cert); + } + if(env_service_key && env_service_key != *service_key) + { + globus_libc_free(env_service_key); + } + if(reg_service_cert && reg_service_cert != *service_cert) + { + globus_libc_free(reg_service_cert); + } + if(reg_service_key && reg_service_key != *service_key) + { + globus_libc_free(reg_service_key); + } + if(installed_service_cert && installed_service_cert != *service_cert) + { + globus_libc_free(installed_service_cert); + } + if(installed_service_key && installed_service_key != *service_key) + { + globus_libc_free(installed_service_key); + } + if(local_service_cert && local_service_cert != *service_cert) + { + globus_libc_free(local_service_cert); + } + if(local_service_key && local_service_key != *service_key) + { + globus_libc_free(local_service_key); + } + if(default_service_cert && default_service_cert != service_cert) + { + globus_libc_free(default_service_cert); + } + if(default_service_key && default_service_key != service_key) + { + globus_libc_free(default_service_key); + } + if (home) { + free(home); + home = NULL; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * WIN32 - Get Proxy Filename + * @ingroup globus_gsi_sysconfig_win32 + */ +/* @{ */ +/** + * Get the proxy cert filename based on the following + * search order: + * + * <ol> + * <li> X509_USER_PROXY environment variable - This environment variable + * is set by the at run time for the specific application. If + * the proxy_file_type variable is set to GLOBUS_PROXY_OUTPUT + * (a proxy filename for writing is requested), + * and the X509_USER_PROXY is set, this will be the + * resulting value of the user_proxy filename string passed in. If the + * proxy_file_type is set to GLOBUS_PROXY_INPUT and X509_USER_PROXY is + * set, but the file it points to does not exist, + * or has some other readability issues, the + * function will continue checking using the other methods available. + * + * <li> check the registry key: x509_user_proxy. Just as with + * the environment variable, if the registry key is set, and proxy_file_type + * is GLOBUS_PROXY_OUTPUT, the string set to be the proxy + * filename will be this registry + * key's value. If proxy_file_type is GLOBUS_PROXY_INPUT, and the + * file doesn't exist, the function will check the next method + * for the proxy's filename. + * + * <li> Check the default location for the proxy file. The default + * location should be + * set to reside in the temp directory on that host, with the filename + * taking the format: x509_u<user id> + * where <user id> is some unique string for that user on the host + * </ol> + * + * @param user_proxy + * the proxy filename of the user + * + * @return + * GLOBUS_SUCCESS or an error object identifier + */ +globus_result_t +globus_gsi_sysconfig_get_proxy_filename_win32( + char ** user_proxy, + globus_gsi_proxy_file_type_t proxy_file_type) +{ + char * env_user_proxy = NULL; + char * env_value = NULL; + char * default_user_proxy = NULL; + char * reg_user_proxy = NULL; + HKEY hkDir = NULL; + char val_user_proxy[512]; + int len; + globus_result_t result; + char * user_id_string; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_proxy_filename_win32"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *user_proxy = NULL; + + if((env_value = getenv(X509_USER_PROXY)) != NULL && + (result = globus_i_gsi_sysconfig_create_key_string( + user_proxy, + & env_user_proxy, + getenv(X509_USER_PROXY))) != GLOBUS_SUCCESS) + { + goto error_exit; + } + + /* check if the proxy file type is for writing */ + if(!(*user_proxy) && env_user_proxy && proxy_file == GLOBUS_PROXY_OUTPUT) + { + *user_proxy = env_user_proxy; + } + + if (!(*user_proxy)) + { + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); + lval = sizeof(val_user_proxy)-1; + if (hkDir && (RegQueryValueEx(hkDir, "x509_user_proxy", 0, &type, + val_user_proxy, &lval) == ERROR_SUCCESS)) + { + if((result = globus_i_gsi_sysconfig_create_key_string( + proxy_cert, + & reg_user_proxy, + val_user_proxy)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + RegCloseKey(hkDir); + } + + if(!(*user_proxy) && reg_user_proxy && proxy_file == GLOBUS_PROXY_OUTPUT) + { + *user_proxy = reg_user_proxy; + } + + if (!user_proxy) + { + if((result = GLOBUS_GSI_SYSCONFIG_GET_USER_ID_STRING( + &user_id_string)) + != GLOBUS_SUCCESS) + { + goto error_exit; + } + if((result = globus_i_gsi_sysconfig_create_key_string( + user_proxy, + & default_user_proxy, + "%s%s%s%s", + DEFAULT_SECURE_TMP_DIR, + FILE_SEPERATOR, + X509_USER_PROXY_FILE, + user_id_string)) != GLOBUS_SUCCESS) + { + goto error_exit; + } + } + + if(!(*user_proxy) && + default_user_proxy && + proxy_file_type == GLOBUS_PROXY_FILE_OUTPUT) + { + *user_proxy = default_user_proxy; + } + + if(!(*user_proxy)) + { + result = GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PROXY_FILENAME, + ("A file location for%s the proxy cert could be found in: \n" + "1) env. var. X509_USER_PROXY=%s\n" + "2) registry key x509_user_proxy: %s\n" + "3) %s\n", + (proxy_file_type == GLOBUS_PROXY_FILE_INPUT) ? "" : " writing", + env_user_proxy, + reg_user_proxy, + default_user_proxy)); + + goto error_exit; + } + + result = GLOBUS_SUCCESS; + goto done; + + error_exit: + + if(*user_proxy) + { + globus_libc_free(*user_proxy); + *user_proxy = NULL; + } + + done: + + if(reg_user_proxy && (reg_user_proxy != (*user_proxy))) + { + globus_libc_free(reg_user_proxy); + } + if(default_user_proxy && (default_user_proxy != (*default_user_proxy))) + { + globus_libc_free(default_user_proxy); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +globus_result_t +globus_gsi_sysconfig_get_ca_cert_file_win32( + char * ca_cert_dir, + globus_fifo_t * ca_cert_list) +{ + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_get_ca_cert_file_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error SLANG: need to fill this in + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + +globus_result_t +globus_gsi_sysconfig_remove_all_owned_files_win32( + char * default_filename) +{ + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_remove_all_owned_files_win32"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error SLANG: need to fill this in + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + +globus_result_t +globus_gsi_sysconfig_get_gridmap_filename_win32( + char ** filename) +{ + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_get_gridmap_filename_win32"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + +#error SLANG: need to fill this in + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + +/* END WIN32 SYSCONFIG DEFINITIONS */ + +#else + +/* BEGIN UNIX SYSCONFIG DEFINITIONS */ + + +#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL + +/** + * UNIX - Set Key Permissions + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Set the file permissions of a file to read only by the user + * which are the permissions that should be set for all private keys. + * + * @param filename + * + * @return + * GLOBUS_SUCCESS or an error object id + */ +globus_result_t +globus_gsi_sysconfig_set_key_permissions_unix( + char * filename) +{ + globus_result_t result = GLOBUS_SUCCESS; + globus_gsi_statcheck_t status; + static char * _function_name_ = + "globus_gsi_sysconfig_set_key_permissions_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + result = globus_gsi_sysconfig_file_exists_unix( + filename, + &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_SETTING_PERMS); + goto exit; + } + + if(status != GLOBUS_FILE_VALID && + status != GLOBUS_FILE_DIR) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_SETTING_PERMS, + ("Error setting permissions of file: %s %s", + filename, + globus_l_gsi_sysconfig_status_strings[status])); + goto exit; + } + + if(chmod(filename, S_IRUSR|S_IWUSR) < 0) + { + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_SETTING_PERMS, + __FILE__":%d:%s: Error setting permissions to " + "user read only of file: %s\n", + __LINE__, + _function_name_, + filename)); + goto exit; + } + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get User ID + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get a unique string representing the current user. This is just + * the uid converted to a string. + * + * @param user_id_string + * A unique string representing the user + * + * @return + * GLOBUS_SUCCESS unless an error occurred + */ +globus_result_t +globus_gsi_sysconfig_get_user_id_string_unix( + char ** user_id_string) +{ + uid_t uid; + int len; + globus_result_t result; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_user_id_string_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + uid = getuid(); + + len = globus_libc_printf_length("%d",uid); + + len++; + + if((*user_id_string = malloc(len)) == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + globus_libc_snprintf(*user_id_string,len,"%d",uid); + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * Unix - Get Username + * @ingroup globus_i_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the username of the current user. + */ +globus_result_t +globus_gsi_sysconfig_get_username_unix( + char ** username) +{ + globus_result_t result = GLOBUS_SUCCESS; + struct passwd pwd; + struct passwd * pwd_result; + char * buf; + int buf_len; + static char * _function_name_ = + "globus_gsi_sysconfig_get_username_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + /* the below seems to be fairly portable */ + + buf_len = sysconf(_SC_GETPW_R_SIZE_MAX) + 1; + + buf = malloc(buf_len); + + if(buf == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + if(globus_libc_getpwuid_r(geteuid(), + &pwd, + buf, + buf_len, + &pwd_result) != 0) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PW_ENTRY, + ("Error occured for uid: %d",geteuid())); + goto exit; + } + + if(pwd_result == NULL || pwd_result->pw_name == NULL) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PW_ENTRY, + ("Error occured for uid: %d",geteuid())); + goto exit; + } + + *username = malloc(strlen(pwd_result->pw_name) + 1); + + if(!*username) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + strncpy(*username, pwd_result->pw_name, + strlen(pwd_result->pw_name) + 1); + + exit: + + if(buf != NULL) + { + free(buf); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get Process ID + * @ingroup globus_i_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get a unique string representing the current process. This is just + * the pid converted to a string. + * + * @param proc_id_string + * A unique string representing the process + * + * @return + * GLOBUS_SUCCESS unless an error occurred + */ +globus_result_t +globus_gsi_sysconfig_get_proc_id_string_unix( + char ** proc_id_string) +{ + pid_t pid; + int len; + globus_result_t result; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_proc_id_string_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + pid = getpid(); + + len = globus_libc_printf_length("%d",pid); + + len++; + + if((*proc_id_string = malloc(len)) == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + globus_libc_snprintf(*proc_id_string,len,"%d",pid); + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +#endif + + +/** + * @name UNIX - Make Absolute Path + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Make the filename into an absolute path string based + * on the current working directory. + * + * @param filename + * the filename to get the absolute path of. + * @param absolute_path + * The resulting absolute path. This needs to + * be freed when no longer needed. + * @return + * GLOBUS_SUCCESS if no error occurred, otherwise + * an error object ID is returned + */ +globus_result_t +globus_gsi_sysconfig_make_absolute_path_for_filename_unix( + char * filename, + char ** absolute_path) +{ + int length; + char * cwd = NULL; + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_make_absolute_path_for_filename_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if(filename[0] != '/') + { + result = GLOBUS_GSI_SYSCONFIG_GET_CURRENT_WORKING_DIR(&cwd); + if(result != GLOBUS_SUCCESS) + { + cwd = NULL; + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CWD); + goto exit; + } + + length = strlen(cwd) + strlen(filename) + 2; + + *absolute_path = malloc(length); + if(!*absolute_path) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + globus_libc_snprintf(*absolute_path, length, "%s/%s", cwd, filename); + } + else + { + length = strlen(filename) + 1; + + *absolute_path = malloc(length); + if(!*absolute_path) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + globus_libc_snprintf(*absolute_path, length, "%s", filename); + } + + exit: + + if(cwd != NULL) + { + free(cwd); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + + +/** + * @name WIN32 - Split Directory and Filename + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Split the directory and filename portions of a filename string + * into two separate strings + * + * @param full_filename + * The filename to split. Splits on the last occurrance of '/' + * where the directory is everything before the last '/', and + * the filename is everything after. + * @param dir_string + * The directory portion of the filename string. If no '/' is found + * throughout the string, this variable points to NULL. + * This needs to be freed when no longer needed. + * @param filename_string + * The filename portion of the filename string. If no '/' is found + * throughout, this variable is a duplicate of the full_filename + * parameter. This needs to be freed when no longer needed. + * + * @return + * GLOBUS_SUCCESS if no error occurred. Otherwise an error object ID + * is returned. + */ +globus_result_t +globus_gsi_sysconfig_split_dir_and_filename_unix( + char * full_filename, + char ** dir_string, + char ** filename_string) +{ + int dir_string_length; + int filename_string_length; + char * split_index = NULL; + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_split_dir_and_filename_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *dir_string = NULL; + *filename_string = NULL; + + split_index = strrchr(full_filename, '/'); + if(!split_index) + { + *dir_string = NULL; + filename_string_length = strlen(full_filename) + 1; + *filename_string = malloc(filename_string_length); + if(!*filename_string) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + globus_libc_snprintf(*filename_string, filename_string_length, + "%s", full_filename); + } + else + { + dir_string_length = split_index - full_filename + 1; + + *dir_string = malloc(dir_string_length); + + if(!*dir_string) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + globus_libc_snprintf(*dir_string, + dir_string_length, "%s", full_filename); + + filename_string_length = strlen(full_filename) - dir_string_length + 1; + + *filename_string = malloc(filename_string_length); + + if(!*filename_string) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + if(*dir_string) + { + free(*dir_string); + } + goto exit; + } + + globus_libc_snprintf(*filename_string, + filename_string_length, "%s", + &full_filename[dir_string_length]); + } + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + + +/** + * @name UNIX - Get Current Working Directory + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the current working directory on the system. + * + * @param working_dir + * The current working directory + * @return + * GLOBUS_SUCCESS or an error object identifier + */ +globus_result_t +globus_gsi_sysconfig_get_current_working_dir_unix( + char ** working_dir) +{ + globus_result_t result = GLOBUS_SUCCESS; + char * buffer = NULL; + char * result_buffer = NULL; + int length = 128; + static char * _function_name_ = + "globus_gsi_sysconfig_get_current_working_dir_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + buffer = malloc(length); + if(!buffer) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + while(1) + { + result_buffer = getcwd(buffer, length); + if(!result_buffer && errno == ERANGE) + { + length *= 2; + if(!(result_buffer = realloc(buffer, length))) + { + free(buffer); + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + buffer = result_buffer; + } + else if(!result_buffer) + { + result = + globus_error_put(globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_ERRNO, + "%s:%d: Couldn't get the current working directory", + __FILE__, __LINE__)); + } + else + { + break; + } + } + + *working_dir = result_buffer; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get HOME Directory + * @ingroup globus_i_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the HOME Directory of the current user. Should + * be the $HOME environment variable. + * + * @param home_dir + * The home directory of the current user + * @return + * GLOBUS_SUCCESS if no error occured, otherwise + * an error object is returned. + */ +globus_result_t +globus_gsi_sysconfig_get_home_dir_unix( + char ** home_dir, + globus_gsi_statcheck_t * status) +{ + char * temp_home_dir; + struct passwd pwd; + struct passwd * pwd_result; + char * buf; + int buf_len; + globus_result_t result; + static char * _function_name_ = + "globus_i_gsi_sysconfig_get_home_dir_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *home_dir = NULL; + + /* the below seems to be fairly portable */ + + buf_len = sysconf(_SC_GETPW_R_SIZE_MAX) + 1; + + buf = malloc(buf_len); + + if(buf == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + if(globus_libc_getpwuid_r(geteuid(), + &pwd, + buf, + buf_len, + &pwd_result) != 0) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PW_ENTRY, + ("Error occured for uid: %d",geteuid())); + goto exit; + } + + if(pwd_result == NULL || pwd_result->pw_dir == NULL) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PW_ENTRY, + ("Error occured for uid: %d",geteuid())); + goto exit; + } + + temp_home_dir = malloc(strlen(pwd_result->pw_dir) + 1); + strncpy(temp_home_dir, pwd_result->pw_dir, + strlen(pwd_result->pw_dir) + 1); + + if(temp_home_dir) + { + result = GLOBUS_GSI_SYSCONFIG_FILE_EXISTS(temp_home_dir, status); + if(result != GLOBUS_SUCCESS) + { + globus_object_t * error_obj; + free(temp_home_dir); + error_obj = globus_error_get(result); + globus_object_free(error_obj); + result = GLOBUS_SUCCESS; + *status = GLOBUS_FILE_INVALID; + goto exit; + } + + *home_dir = temp_home_dir; + } + else + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_HOME_DIR, + ("Could not get a defined HOME directory for user id: %d\n", + geteuid())); + goto exit; + } + + result = GLOBUS_SUCCESS; + + exit: + + if(buf != NULL) + { + free(buf); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - File Exists + * @ingroup globus_i_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Check if the file exists + * + * @param filename the filename of the file to check for + * @param status the resulting status of the file + * + * @return + * GLOBUS_SUCCESS for almost all cases (even if the file + * doesn't exist), otherwise an error object identifier + * wrapping the system errno is returned + */ +globus_result_t +globus_gsi_sysconfig_file_exists_unix( + const char * filename, + globus_gsi_statcheck_t * status) +{ + struct stat stx; + globus_result_t result; + + static char * _function_name_ = + "globus_i_gsi_sysconfig_file_exists_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if (stat(filename,&stx) == -1) + { + switch(errno) + { + case ENOENT: + case ENOTDIR: + *status = GLOBUS_FILE_DOES_NOT_EXIST; + result = GLOBUS_SUCCESS; + goto exit; + + case EACCES: + + *status = GLOBUS_FILE_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + + default: + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_CHECKING_FILE_EXISTS, + __FILE__":%d:%s: Error getting status " + "of certificate directory: %s\n", + __LINE__, + _function_name_, + filename)); + goto exit; + + } + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx,sizeof(stx),2); + + if (stx.st_size == 0) + { + *status = GLOBUS_FILE_ZERO_LENGTH; + result = GLOBUS_SUCCESS; + goto exit; + } + + if(stx.st_mode & S_IFDIR) + { + *status = GLOBUS_FILE_DIR; + } + else if(stx.st_mode & (S_IFREG | S_IFLNK)) + { + *status = GLOBUS_FILE_VALID; + } + else + { + *status = GLOBUS_FILE_INVALID; + } + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + + +/** + * UNIX - Check File Status for Key + * @ingroup globus_i_gsi_sysconfig_unix + */ +/* @{ */ +/** + * This is a convenience function used to check the status of a + * private key file. The desired status is only the current user has + * ownership and read permissions, everyone else should not be able + * to access it. + * + * @param filename + * The name of the file to check the status of + * @param status + * The status of the file being checked + * see @ref globus_gsi_statcheck_t for possible values + * of this variable + * + * @return + * GLOBUS_SUCCESS if the status of the file was able + * to be determined. Otherwise, an error object + * identifier + * + * @see globus_gsi_statcheck_t + */ +globus_result_t +globus_gsi_sysconfig_check_keyfile_unix( + const char * filename, + globus_gsi_statcheck_t * status) +{ + struct stat stx; + globus_result_t result; + static char * _function_name_ = + "globus_i_gsi_sysconfig_check_keyfile_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if (stat(filename,&stx) == -1) + { + switch (errno) + { + case ENOENT: + case ENOTDIR: + *status = GLOBUS_FILE_DOES_NOT_EXIST; + result = GLOBUS_SUCCESS; + goto exit; + + case EACCES: + + *status = GLOBUS_FILE_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + + default: + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + __FILE__":%d:%s: Error getting status of keyfile: %s\n", + __LINE__, + _function_name_, + filename)); + goto exit; + } + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx,sizeof(stx),2); + + if (stx.st_uid != getuid()) + { + *status = GLOBUS_FILE_NOT_OWNED; + result = GLOBUS_SUCCESS; + goto exit; + } + + /* check that the key file is not x by user, or rwx by group or others */ + if (stx.st_mode & (S_IXUSR | + S_IRGRP | S_IWGRP | S_IXGRP | + S_IROTH | S_IWOTH | S_IXOTH)) + { + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (stderr, "checkstat:%s:mode:%o\n", filename, stx.st_mode)); + + *status = GLOBUS_FILE_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + } + + if (stx.st_size == 0) + { + *status = GLOBUS_FILE_ZERO_LENGTH; + result = GLOBUS_SUCCESS; + goto exit; + } + + if(stx.st_mode & S_IFDIR) + { + *status = GLOBUS_FILE_DIR; + } + else if(stx.st_mode & (S_IFLNK | S_IFREG)) + { + *status = GLOBUS_FILE_VALID; + } + else + { + *status = GLOBUS_FILE_INVALID; + } + + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * UNIX - Check File Status for Cert + * @ingroup globus_i_gsi_sysconfig_unix + */ +/* @{ */ +/** + * This is a convenience function used to check the status of a + * certificate file. The desired status is the current user has + * ownership and read/write permissions, while group and others only + * have read permissions. + * + * @param filename + * The name of the file to check the status of + * @param status + * The status of the file being checked + * see @ref globus_gsi_statcheck_t for possible values + * of this variable + * + * @return + * GLOBUS_SUCCESS if the status of the file was able + * to be determined. Otherwise, an error object + * identifier + * + * @see globus_gsi_statcheck_t + */ +globus_result_t +globus_gsi_sysconfig_check_certfile_unix( + const char * filename, + globus_gsi_statcheck_t * status) +{ + struct stat stx; + globus_result_t result; + static char * _function_name_ = + "globus_i_gsi_sysconfig_check_certfile_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if (stat(filename,&stx) == -1) + { + switch (errno) + { + case ENOENT: + case ENOTDIR: + *status = GLOBUS_FILE_DOES_NOT_EXIST; + result = GLOBUS_SUCCESS; + goto exit; + + case EACCES: + + *status = GLOBUS_FILE_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + + default: + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_FILENAME, + __FILE__":%d:%s: Error getting status of cert file %s\n", + __LINE__, + _function_name_, + filename)); + goto exit; + } + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx,sizeof(stx),2); + + if (stx.st_uid != getuid()) + { + *status = GLOBUS_FILE_NOT_OWNED; + result = GLOBUS_SUCCESS; + goto exit; + } + + /* check that the cert file is not x by user, or wx by group or others */ + if (stx.st_mode & (S_IXUSR | + S_IWGRP | S_IXGRP | + S_IWOTH | S_IXOTH)) + { + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (stderr, "checkstat:%s:mode:%o\n",filename,stx.st_mode)); + + *status = GLOBUS_FILE_BAD_PERMISSIONS; + result = GLOBUS_SUCCESS; + goto exit; + } + + if (stx.st_size == 0) + { + *status = GLOBUS_FILE_ZERO_LENGTH; + result = GLOBUS_SUCCESS; + goto exit; + } + + if(stx.st_mode & S_IFDIR) + { + *status = GLOBUS_FILE_DIR; + } + else if(stx.st_mode & (S_IFREG | S_IFLNK)) + { + *status = GLOBUS_FILE_VALID; + } + else + { + *status = GLOBUS_FILE_INVALID; + } + + *status = GLOBUS_FILE_VALID; + result = GLOBUS_SUCCESS; + + exit: + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get Trusted CA Cert Dir + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the Trusted Certificate Directory containing the trusted + * Certificate Authority certificates. This directory is determined + * in the order shown below. Failure in one method results in attempting + * the next. + * + * <ol> + * <li> <b>X509_CERT_DIR environment variable</b> - if this is set, the + * trusted certificates will be searched for in that directory. This + * variable allows the end user to specify the location of trusted + * certificates. + * <li> <b>$HOME/.globus/certificates</b> - If this + * directory exists, and the previous methods of determining the trusted + * certs directory failed, this directory will be used. + * <li> <b>/etc/grid-security/certificates</b> - This location is intended + * to be independant of the globus installation ($GLOBUS_LOCATION), and + * is generally only writeable by the host system administrator. + * <li> <b>$GLOBUS_LOCATION/share/certificates</b> + * </ol> + * + * @param cert_dir + * The trusted certificates directory + * @return + * GLOBUS_SUCCESS if no error occurred, and a sufficient trusted + * certificates directory was found. Otherwise, an error object + * identifier returned. + */ +globus_result_t +globus_gsi_sysconfig_get_cert_dir_unix( + char ** cert_dir) +{ + char * env_cert_dir = NULL; + char * local_cert_dir = NULL; + char * default_cert_dir = NULL; + char * installed_cert_dir = NULL; + globus_result_t result; + char * home = NULL; + char * globus_location; + globus_gsi_statcheck_t status; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_cert_dir_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *cert_dir = NULL; + + if(getenv(X509_CERT_DIR)) + { + result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & env_cert_dir, + & status, + getenv(X509_CERT_DIR)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto error_exit; + } + + if(status != GLOBUS_FILE_DIR) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR, + ("X509_CERT_DIR=%s, but the the path " + "is not a valid directory", env_cert_dir)); + goto error_exit; + } + } + + /* now check for a trusted CA directory in the user's home directory */ + if(!(*cert_dir)) + { + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result != GLOBUS_SUCCESS) + { + home = NULL; + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto error_exit; + } + + if(home && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + & local_cert_dir, + & status, + "%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_TRUSTED_CERT_DIR); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto error_exit; + } + } + } + + /* now look in /etc/grid-security/certificates */ + if (!(*cert_dir)) + { + result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + &installed_cert_dir, + &status, + X509_DEFAULT_TRUSTED_CERT_DIR); + if(result != GLOBUS_SUCCESS) + { + if(status != GLOBUS_FILE_BAD_PERMISSIONS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto error_exit; + } + else + { + globus_object_t * error_obj; + error_obj = globus_error_get(result); + globus_object_free(error_obj); + } + } + } + + /* now look in $GLOBUS_LOCATION/share/certificates */ + if (!(*cert_dir)) + { + globus_location = getenv("GLOBUS_LOCATION"); + + if (globus_location) + { + result = globus_i_gsi_sysconfig_create_cert_dir_string( + cert_dir, + &default_cert_dir, + &status, + "%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_TRUSTED_CERT_DIR); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR); + goto error_exit; + } + } + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (stderr, "Using cert_dir = %s\n", + (*cert_dir ? *cert_dir : "null"))); + + if(!(*cert_dir)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_DIR, + ("The trusted certificates directory could not be " + "found in any of the following locations: \n" + "1) env. var. X509_CERT_DIR=%s\n" + "2) %s\n3) %s\n4) %s\n", + env_cert_dir ? env_cert_dir : "NULL", + local_cert_dir ? local_cert_dir : "NULL", + installed_cert_dir ? installed_cert_dir : "NULL", + default_cert_dir ? default_cert_dir : "NULL")); + + goto error_exit; + } + + result = GLOBUS_SUCCESS; + goto done; + + error_exit: + + if(*cert_dir) + { + globus_libc_free(*cert_dir); + *cert_dir = NULL; + } + + done: + + if(home != NULL) + { + free(home); + } + + if(env_cert_dir && (env_cert_dir != (*cert_dir))) + { + globus_libc_free(env_cert_dir); + } + if(local_cert_dir && (local_cert_dir != (*cert_dir))) + { + globus_libc_free(local_cert_dir); + } + if(installed_cert_dir && (installed_cert_dir != (*cert_dir))) + { + globus_libc_free(installed_cert_dir); + } + if(default_cert_dir && (default_cert_dir != (*cert_dir))) + { + globus_libc_free(default_cert_dir); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + + return result; +} +/* @} */ + +/** + * UNIX - Get User Certificate Filename + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the User Certificate Filename based on the current user's + * environment. The following locations are searched for cert and key + * files in order: + * + * <ol> + * <li>environment variables X509_USER_CERT and X509_USER_KEY + * <li>$HOME/.globus/usercert.pem and + * $HOME/.globus/userkey.pem + * <li>$HOME/.globus/usercred.p12 - this is a PKCS12 credential + * </ol> + * + * @param user_cert + * pointer the filename of the user certificate + * @param user_key + * pointer to the filename of the user key + * @return + * GLOBUS_SUCCESS if the cert and key files were found in one + * of the possible locations, otherwise an error object identifier + * is returned + */ +globus_result_t +globus_gsi_sysconfig_get_user_cert_filename_unix( + char ** user_cert, + char ** user_key) +{ + char * home = NULL; + char * env_user_cert = NULL; + char * env_user_key = NULL; + char * default_user_cert = NULL; + char * default_user_key = NULL; + char * default_pkcs12_user_cred = NULL; + globus_gsi_statcheck_t status; + globus_result_t result; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_user_cert_filename_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *user_cert = NULL; + *user_key = NULL; + + /* first, check environment variables for valid filenames */ + + if(getenv(X509_USER_CERT)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + user_cert, + & env_user_cert, + & status, + getenv(X509_USER_CERT)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + if(status != GLOBUS_FILE_VALID) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + (X509_USER_CERT"=%s %s", + env_user_cert, + globus_l_gsi_sysconfig_status_strings[status])); + goto done; + } + + } + + if(getenv(X509_USER_KEY)) + { + result = globus_i_gsi_sysconfig_create_key_string( + user_key, + & env_user_key, + & status, + getenv(X509_USER_KEY)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if(status != GLOBUS_FILE_VALID) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + (X509_USER_KEY"=%s %s", + env_user_key, + globus_l_gsi_sysconfig_status_strings[status])); + goto done; + } + } + + /* next, check default locations */ + if(!(*user_cert) || !(*user_key)) + { + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result != GLOBUS_SUCCESS) + { + home = NULL; + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + if(home && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_cert_string( + user_cert, + & default_user_cert, + & status, + "%s%s%s", + home, + FILE_SEPERATOR, + X509_DEFAULT_USER_CERT); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + user_key, + & default_user_key, + & status, + "%s%s%s", + home, + FILE_SEPERATOR, + X509_DEFAULT_USER_KEY); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if((*user_cert) && !(*user_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("User certificate is at: %s, but a user key " + "could not be found at: %s", + *user_cert, default_user_key)); + *user_cert = NULL; + goto done; + } + + if((*user_key) && !(*user_cert)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("User key is at: %s, but a user certificate " + "could not be found at: %s", + *user_key, default_user_cert)); + *user_key = NULL; + goto done; + } + } + } + + /* if the cert & key don't exist in the default locations + * or those specified by the environment variables, a + * pkcs12 cert will be searched for + */ + if(!(*user_cert) && !(*user_key)) + { + if(home) + { + free(home); + home = NULL; + } + + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if(home && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_key_string( + user_key, + & default_pkcs12_user_cred, + & status, + "%s%s%s", + home, + FILE_SEPERATOR, + X509_DEFAULT_PKCS12_FILE); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + *user_cert = *user_key; + } + } + + if(!(*user_cert)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + ("The user cert could not be found in: \n" + "1) env. var. X509_USER_CERT=%s\n" + "2) %s\n3) %s\n\n", + env_user_cert ? env_user_cert : "NULL", + default_user_cert ? default_user_cert : "NULL", + default_pkcs12_user_cred ? default_pkcs12_user_cred : "NULL")); + goto done; + } + + if(!(*user_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("The user key could not be found in:\n," + "1) env. var. X509_USER_KEY=%s\n" + "2) %s\n3) %s\n\n", + env_user_key ? env_user_key : "NULL", + default_user_key ? default_user_key : "NULL", + default_pkcs12_user_cred ? default_pkcs12_user_cred : "NULL")); + goto done; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (stderr,"Using x509_user_cert=%s\n x509_user_key =%s\n", + *user_cert, *user_key)); + + result = GLOBUS_SUCCESS; + + done: + + if(env_user_cert && env_user_cert != (*user_cert)) + { + globus_libc_free(env_user_cert); + } + if(env_user_key && env_user_key != (*user_key)) + { + globus_libc_free(env_user_key); + } + if(default_user_cert && default_user_cert != (*user_cert)) + { + globus_libc_free(default_user_cert); + } + if(default_user_key && default_user_key != (*user_key)) + { + globus_libc_free(default_user_key); + } + if(home) + { + free(home); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get Host Certificate and Key Filenames + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the Host Certificate and Key Filenames based on the current user's + * environment. The host cert and key are searched for in the following + * locations (in order): + * + * <ol> + * <li>X509_USER_CERT and X509_USER_KEY environment variables + * <li>registry keys x509_user_cert and x509_user_key in software\Globus\GSI + * <li>SLANG: NOT DETERMINED - this is the default location + * <li><GLOBUS_LOCATION>\etc\host[cert|key].pem + * <li><users home directory>\.globus\host[cert|key].pem + * </ol> + * + * @param host_cert + * pointer to the host certificate filename + * @param host_key + * pointer to the host key filename + * + * @return + * GLOBUS_SUCCESS if the host cert and key were found, otherwise + * an error object identifier is returned + */ +globus_result_t +globus_gsi_sysconfig_get_host_cert_filename_unix( + char ** host_cert, + char ** host_key) +{ + char * home = NULL; + char * env_host_cert = NULL; + char * env_host_key = NULL; + char * default_host_cert = NULL; + char * default_host_key = NULL; + char * installed_host_cert = NULL; + char * installed_host_key = NULL; + char * local_host_cert = NULL; + char * local_host_key = NULL; + char * globus_location = NULL; + globus_gsi_statcheck_t status; + globus_result_t result; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_host_cert_filename_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *host_cert = NULL; + *host_key = NULL; + + /* first check environment variables for valid filenames */ + + if(getenv(X509_USER_CERT)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & env_host_cert, + & status, + getenv(X509_USER_CERT)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + if(status != GLOBUS_FILE_VALID) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + (X509_USER_CERT"=%s %s", + env_host_cert, + globus_l_gsi_sysconfig_status_strings[status])); + goto done; + } + } + + if(getenv(X509_USER_KEY)) + { + result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & env_host_key, + & status, + getenv(X509_USER_KEY)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + if(status != GLOBUS_FILE_VALID) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + (X509_USER_CERT"=%s %s", + env_host_key, + globus_l_gsi_sysconfig_status_strings[status])); + goto done; + } + } + +/* G.Ganis 16/4/2003 begin */ + /* now check validity of files found (if any) */ + if (*host_cert ) + { + result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & default_host_cert, + & status, + "%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + } + if (*host_key ) + { + result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & default_host_key, + & status, + "%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + } +/* G.Ganis 16/4/2003 end */ + + + /* now check default locations for valid filenames */ + if(!(*host_cert) || !(*host_key)) + { + + /* G.Ganis 16/4/2003 begin */ + /* + result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & default_host_cert, + & status, + "%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & default_host_key, + & status, + "%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + */ + /* G.Ganis 16/4/2003 end */ + + if((*host_cert) && !(*host_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Host certificate is at: %s, but a host cert " + "coult not be found at: %s", + *host_cert, default_host_key)); + free(*host_cert); + goto done; + } + + if((*host_key) && !(*host_cert)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Host key is at: %s, but a host certificate " + "could not be found at: %s", + *host_key, default_host_cert)); + free(*host_key); + goto done; + } + } + + /* now check installed location for host cert */ + if(!(*host_cert) || !(*host_key)) + { + globus_location = getenv("GLOBUS_LOCATION"); + + if(globus_location) + { + result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & installed_host_cert, + & status, + "%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & installed_host_key, + & status, + "%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if((*host_cert) && !(*host_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Host certificate is at: %s, but a host cert " + "coult not be found at: %s", + *host_cert, installed_host_key)); + free(*host_cert); + goto done; + } + + if((*host_key) && !(*host_cert)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Host key is at: %s, but a host certificate " + "could not be found at: %s", + *host_key, installed_host_cert)); + free(*host_key); + goto done; + } + } + } + + if(!(*host_cert) || !(*host_key)) + { + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + home = NULL; + goto done; + } + + if(home && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_cert_string( + host_cert, + & local_host_cert, + & status, + "%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + host_key, + & local_host_key, + & status, + "%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + X509_HOST_PREFIX, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if((*host_cert) && !(*host_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Host certificate is at: %s, but a host cert " + "coult not be found at: %s", + *host_cert, local_host_key)); + *host_cert = NULL; + goto done; + } + + if((*host_key) && !(*host_cert)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Host key is at: %s, but a host certificate " + "could not be found at: %s", + *host_key, local_host_cert)); + *host_key = NULL; + goto done; + } + } + } + + if(!(*host_cert) || !(*host_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_FILENAME, + ("The host cert could not be found in: \n" + "1) env. var. X509_USER_CERT=%s\n" + "2) %s\n3) %s\n4) %s\n\n" + "The host key could not be found in:\n" + "1) env. var. X509_USER_KEY=%s\n" + "2) %s\n3) %s\n4) %s\n", + env_host_cert ? env_host_cert : "NULL", + default_host_cert ? default_host_cert : "NULL", + installed_host_cert ? installed_host_cert : "NULL", + local_host_cert ? local_host_cert : "NULL", + env_host_key ? env_host_key : "NULL", + default_host_key ? default_host_key : "NULL", + installed_host_key ? installed_host_key : "NULL", + local_host_key ? local_host_key : "NULL")); + + goto done; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (stderr, "Using x509_user_cert=%s\n x509_user_key =%s\n", + *host_cert , *host_key)); + + result = GLOBUS_SUCCESS; + + done: + + if(env_host_cert && env_host_cert != *host_cert) + { + globus_libc_free(env_host_cert); + } + if(env_host_key && env_host_key != *host_key) + { + globus_libc_free(env_host_key); + } + if(installed_host_cert && installed_host_cert != *host_cert) + { + globus_libc_free(installed_host_cert); + } + if(installed_host_key && installed_host_key != *host_key) + { + globus_libc_free(installed_host_key); + } + if(local_host_cert && local_host_cert != *host_cert) + { + globus_libc_free(local_host_cert); + } + if(local_host_key && local_host_key != *host_key) + { + globus_libc_free(local_host_key); + } + if(default_host_cert && default_host_cert != *host_cert) + { + globus_libc_free(default_host_cert); + } + if(default_host_key && default_host_key != *host_key) + { + globus_libc_free(default_host_key); + } + + if(home) + { + free(home); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get Service Certificate and Key Filenames + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the Service Certificate Filename based on the current user's + * environment. The host cert and key are searched for in the following + * locations (in order): + * + * <ol> + * <li>X509_USER_CERT and X509_USER_KEY environment variables + * <li>/etc/grid-security/{service_name}/{service_name}[cert|key].pem + * <li>GLOBUS_LOCATION\etc\{service_name}\{service_name}[cert|key].pem + * So for example, if my service was named: myservice, the location + * of the certificate would be: + * GLOBUS_LOCATION\etc\myservice\myservicecert.pem + * <li><users home>\.globus\{service_name}\{service_name}[cert|key].pem + * </ol> + * + * @param service_name + * The name of the service which allows us to determine the + * locations of cert and key files to look for + * @param service_cert + * pointer to the host certificate filename + * @param service_key + * pointer to the host key filename + * + * @return + * GLOBUS_SUCCESS if the service cert and key were found, otherwise + * an error object identifier + */ +globus_result_t +globus_gsi_sysconfig_get_service_cert_filename_unix( + char * service_name, + char ** service_cert, + char ** service_key) +{ + char * home = NULL; + char * env_service_cert = NULL; + char * env_service_key = NULL; + char * default_service_cert = NULL; + char * default_service_key = NULL; + char * installed_service_cert = NULL; + char * installed_service_key = NULL; + char * local_service_cert = NULL; + char * local_service_key = NULL; + char * globus_location = NULL; + globus_gsi_statcheck_t status; + globus_result_t result; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_service_cert_filename_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *service_cert = NULL; + *service_key = NULL; + + /* first check environment variables for valid filenames */ + + if(getenv(X509_USER_CERT)) + { + result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & env_service_cert, + & status, + getenv(X509_USER_CERT)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + if(status != GLOBUS_FILE_VALID || !(*service_cert)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + (X509_USER_CERT"=%s %s", + getenv(X509_USER_CERT), + globus_l_gsi_sysconfig_status_strings[status])); + goto done; + } + } + + if(getenv(X509_USER_KEY)) + { + result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & env_service_key, + & status, + getenv(X509_USER_KEY)); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if(status != GLOBUS_FILE_VALID || !*service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("X509_USER_KEY=%s is not a valid service key file", + env_service_key)); + goto done; + } + } + + /* now check default locations for valid filenames */ + if(!(*service_cert) || !(*service_key)) + { + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + home = NULL; + goto done; + } + + if(home && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & default_service_cert, + & status, + "%s%s%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & default_service_key, + & status, + "%s%s%s%s%s%s", + X509_DEFAULT_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if(*service_cert && !*service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("The service certificate was found at: %s, ", + "but no service key could be found at: %s", + *service_cert, default_service_key)); + goto done; + } + + if(!*service_cert && *service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING, + ("The service key was found at: %s, " + "but no service cert could be found at: %s", + *service_key, default_service_cert)); + goto done; + } + } + } + + /* now check intstalled location for service cert */ + if(!(*service_cert) || !(*service_key)) + { + globus_location = getenv("GLOBUS_LOCATION"); + + if(globus_location) + { + result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & installed_service_cert, + & status, + "%s%s%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & installed_service_key, + & status, + "%s%s%s%s%s%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING); + goto done; + } + + if(*service_cert && !*service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Service certificate was found at: %s, but no " + "service key was found at: %s", + *service_cert, installed_service_key)); + goto done; + } + + if(!*service_cert && *service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Service key was found at: %s, but no " + "service certificate was found at: %s", + *service_key, installed_service_cert)); + goto done; + } + } + } + + if(!(*service_cert) || !(*service_key)) + { + /* need to change this if I ever fix the status mess */ + if(home) + { + free(home); + home = NULL; + } + + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home, &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + home = NULL; + goto done; + } + + if(home && status == GLOBUS_FILE_DIR) + { + result = globus_i_gsi_sysconfig_create_cert_string( + service_cert, + & local_service_cert, + & status, + "%s%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_CERT_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + service_key, + & local_service_key, + & status, + "%s%s%s%s%s%s%s%s", + home, + FILE_SEPERATOR, + X509_LOCAL_CERT_DIR, + FILE_SEPERATOR, + service_name, + FILE_SEPERATOR, + service_name, + X509_KEY_SUFFIX); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_STRING); + goto done; + } + + if(*service_cert && !*service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Service certificate was found at: %s, but no " + "service key was found at: %s", + *service_cert, local_service_key)); + goto done; + } + + if(!*service_cert && *service_key) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_KEY_STRING, + ("Service key was found at: %s, but no " + "service certificate was found at: %s", + *service_key, local_service_cert)); + goto done; + } + } + else + { + globus_object_t * error_obj; + error_obj = globus_error_get(result); + globus_object_free(error_obj); + } + } + + if(!(*service_cert) || !(*service_key)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CERT_FILENAME, + ("\nThe service cert could not be found in: \n" + "1) env. var. X509_USER_CERT=%s\n" + "2) %s\n3) %s\n4) %s\n\n" + "The service key could not be found in:\n" + "1) env. var. X509_USER_KEY=%s\n" + "2) %s\n3) %s\n4) %s\n", + env_service_cert ? env_service_cert : "NULL", + default_service_cert ? default_service_cert : "NULL", + installed_service_cert ? installed_service_cert : "NULL", + local_service_cert ? local_service_cert : "NULL", + env_service_key ? env_service_key : "NULL", + default_service_key ? default_service_key : "NULL", + installed_service_key ? installed_service_key : "NULL", + local_service_key ? local_service_key : "NULL")); + + goto done; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_FPRINTF( + 2, (stderr, "Using x509_user_cert=%s\n x509_user_key =%s\n", + *service_cert , *service_key)); + + result = GLOBUS_SUCCESS; + + done: + + if(env_service_cert && env_service_cert != *service_cert) + { + globus_libc_free(env_service_cert); + } + if(env_service_key && env_service_key != *service_key) + { + globus_libc_free(env_service_key); + } + if(installed_service_cert && installed_service_cert != *service_cert) + { + globus_libc_free(installed_service_cert); + } + if(installed_service_key && installed_service_key != *service_key) + { + globus_libc_free(installed_service_key); + } + if(local_service_cert && local_service_cert != *service_cert) + { + globus_libc_free(local_service_cert); + } + if(local_service_key && local_service_key != *service_key) + { + globus_libc_free(local_service_key); + } + if(default_service_cert && default_service_cert != *service_cert) + { + globus_libc_free(default_service_cert); + } + if(default_service_key && default_service_key != *service_key) + { + globus_libc_free(default_service_key); + } + + if(home) + { + free(home); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * UNIX - Get Proxy Filename + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the proxy cert filename based on the following + * search order: + * + * <ol> + * <li> X509_USER_PROXY environment variable - This environment variable + * is set by the at run time for the specific application. If + * the proxy_file_type variable is set to GLOBUS_PROXY_OUTPUT + * (a proxy filename for writing is requested), + * and the X509_USER_PROXY is set, this will be the + * resulting value of the user_proxy filename string passed in. If the + * proxy_file_type is set to GLOBUS_PROXY_INPUT and X509_USER_PROXY is + * set, but the file it points to does not exist, + * or has some other readability issues, the + * function will continue checking using the other methods available. + * + * <li> Check the default location for the proxy file of /tmp/x509_u<user_id> + * where <user id> is some unique string for that user on the host + * </ol> + * + * @param user_proxy + * the proxy filename of the user + * + * @return + * GLOBUS_SUCCESS or an error object identifier + */ +globus_result_t +globus_gsi_sysconfig_get_proxy_filename_unix( + char ** user_proxy, + globus_gsi_proxy_file_type_t proxy_file_type) +{ + char * env_user_proxy = NULL; + char * env_value = NULL; + char * default_user_proxy = NULL; + globus_result_t result; + char * user_id_string = NULL; + globus_gsi_statcheck_t status; + static char * _function_name_ = + "globus_gsi_sysconfig_get_proxy_filename_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *user_proxy = NULL; + + if((env_value = getenv(X509_USER_PROXY))) + { + result = globus_i_gsi_sysconfig_create_key_string( + user_proxy, + & env_user_proxy, + & status, + env_value); + if(proxy_file_type == GLOBUS_PROXY_FILE_OUTPUT && + status == GLOBUS_FILE_DOES_NOT_EXIST) + { + globus_object_t * error_obj; + error_obj = globus_error_get(result); + globus_object_free(error_obj); + + *user_proxy = env_user_proxy; + status = GLOBUS_FILE_VALID; + } + + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PROXY_FILENAME); + goto done; + } + + if(status != GLOBUS_FILE_VALID || !*user_proxy) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PROXY_FILENAME, + (X509_USER_PROXY"=%s %s", + env_user_proxy, + globus_l_gsi_sysconfig_status_strings[status])); + goto done; + } + } + + /* check if the proxy file type is for writing */ + if(!(*user_proxy) && env_user_proxy && + proxy_file_type == GLOBUS_PROXY_FILE_OUTPUT) + { + *user_proxy = env_user_proxy; + } + + if (!*user_proxy) + { + result = GLOBUS_GSI_SYSCONFIG_GET_USER_ID_STRING(&user_id_string); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PROXY_FILENAME); + goto done; + } + + result = globus_i_gsi_sysconfig_create_key_string( + user_proxy, + & default_user_proxy, + & status, + "%s%s%s%s", + DEFAULT_SECURE_TMP_DIR, + FILE_SEPERATOR, + X509_USER_PROXY_FILE, + user_id_string); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PROXY_FILENAME); + goto done; + } + } + + if(!(*user_proxy) && + default_user_proxy && + proxy_file_type == GLOBUS_PROXY_FILE_OUTPUT) + { + *user_proxy = default_user_proxy; + } + + if(!(*user_proxy)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_PROXY_FILENAME, + ("A file location for%s the proxy cert could not be found in: \n" + "1) env. var. X509_USER_PROXY=%s\n" + "2) %s\n", + (proxy_file_type == GLOBUS_PROXY_FILE_INPUT) ? "" : " writing", + env_user_proxy ? env_user_proxy : "NULL", + default_user_proxy ? default_user_proxy : "NULL")); + + goto done; + } + + result = GLOBUS_SUCCESS; + + done: + + if(user_id_string) + { + free(user_id_string); + } + + if(default_user_proxy && (default_user_proxy != (*user_proxy))) + { + globus_libc_free(default_user_proxy); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * @name UNIX - Get Signing Policy Filename + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Get the Signing Policy Filename on the current system, + * based on the CA's subject name, and the trusted certificates + * directory + * + * @param ca_name + * The X509 subject name of the CA to get the signing policy of. + * The hash of the CA is generated from this + * + * @param cert_dir + * The trusted CA certificates directory, containing the singing_policy + * files of the trusted CA's. + * + * @param singing_policy_filename + * The resulting singing_policy filename + * @return + * GLOBUS_SUCCESS if no error occurred, otherwise an error object ID + */ +globus_result_t +globus_gsi_sysconfig_get_signing_policy_filename_unix( + X509_NAME * ca_name, + char * cert_dir, + char ** signing_policy_filename) +{ + char * signing_policy = NULL; + globus_gsi_statcheck_t status; + globus_result_t result = GLOBUS_SUCCESS; + unsigned long hash; + char * ca_cert_dir = NULL; + + static char * _function_name_ = + "globus_gsi_sysconfig_get_signing_policy_filename_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + *signing_policy_filename = NULL; + + if (cert_dir == NULL) + { + result = GLOBUS_GSI_SYSCONFIG_GET_CERT_DIR(&ca_cert_dir); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_SIGNING_POLICY); + goto exit; + } + } + else + { + ca_cert_dir = cert_dir; + } + + if(ca_name == NULL) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_SIGNING_POLICY, + ("NULL parameter ca_name passed to: %s", _function_name_)); + goto exit; + } + + hash = X509_NAME_hash(ca_name); + + signing_policy = globus_gsi_cert_utils_create_string( + "%s%s%08lx%s", + ca_cert_dir, FILE_SEPERATOR, hash, SIGNING_POLICY_FILE_EXTENSION); + + if(signing_policy == NULL) + { + result = GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + + result = GLOBUS_GSI_SYSCONFIG_FILE_EXISTS(signing_policy, &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_SIGNING_POLICY); + goto exit; + } + + if(status == GLOBUS_FILE_VALID) + { + *signing_policy_filename = signing_policy; + } + + exit: + + if(ca_cert_dir != NULL && + cert_dir == NULL) + { + free(ca_cert_dir); + } + + if(signing_policy != NULL && + result != GLOBUS_SUCCESS) + { + free(signing_policy); + *signing_policy_filename = NULL; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * @name UNIX - Get CA Cert Filenames + * @ingroup globus_gsi_sysconfig_unix + */ +/* @{ */ +/** + * Gets a list of trusted CA certificate filenames in + * a trusted CA certificate directory. + * + * @param ca_cert_dir + * The trusted CA certificate directory to get the filenames from + * @param ca_cert_list + * The resulting list of CA certificate filenames. This is a + * a globus list structure. + * @see globus_fifo_t + * @return + * GLOBUS_SUCCESS if no error occurred, otherwise an error object ID + * is returned + */ +globus_result_t +globus_gsi_sysconfig_get_ca_cert_files_unix( + char * ca_cert_dir, + globus_fifo_t * ca_cert_list) +{ + DIR * dir_handle = NULL; + struct dirent * tmp_entry = NULL; + int file_length; + char * full_filename_path = NULL; + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_get_ca_cert_file_unix"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if(!ca_cert_dir) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CA_CERT_FILENAMES, + ("NULL parameter ca_cert_dir passed to function: %s", + _function_name_)); + goto exit; + } + + if(!ca_cert_list) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CA_CERT_FILENAMES, + ("NULL parameter ca_cert_list passed to function: %s", + _function_name_)); + goto exit; + } + + dir_handle = globus_libc_opendir(ca_cert_dir); + if(dir_handle == NULL) + { + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_ERRNO, + "Error opening directory: %s", ca_cert_dir)); + goto exit; + } + + while(globus_libc_readdir_r(dir_handle,&tmp_entry) == 0 && + tmp_entry != NULL) + { + file_length = strlen(tmp_entry->d_name); + /* check the following: + * + * - file length is greater than or equal to 10 + * - first 8 characters are alpha-numeric + * - 9th character is '.' + * - characters after the '.' are numeric + */ + if(file_length >= (X509_HASH_LENGTH + 2) && + (*(tmp_entry->d_name + X509_HASH_LENGTH) == '.') && + (strspn(tmp_entry->d_name, "0123456789abcdefABCDEF") + == X509_HASH_LENGTH) && + (strspn((tmp_entry->d_name + (X509_HASH_LENGTH + 1)), + "0123456789") == (file_length - 9))) + { + full_filename_path = + globus_gsi_cert_utils_create_string( + "%s%s%s", ca_cert_dir, FILE_SEPERATOR, tmp_entry->d_name); + + if(full_filename_path == NULL) + { + globus_free(tmp_entry); + while((full_filename_path = + (char *) globus_fifo_dequeue(ca_cert_list)) != NULL) + { + free(full_filename_path); + } + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_CA_CERT_FILENAMES, + ("Couldn't get full pathname for CA cert")); + goto exit; + } + + globus_fifo_enqueue(ca_cert_list, (void *)full_filename_path); + } + + globus_free(tmp_entry); + } + + exit: + + if(dir_handle != NULL) + { + globus_libc_closedir(dir_handle); + } + + if(tmp_entry != NULL) + { + globus_libc_free(tmp_entry); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; + +} +/* @} */ + +globus_result_t +globus_gsi_sysconfig_remove_all_owned_files_unix( + char * default_filename) +{ + struct stat stx; + char * full_filename = NULL; + globus_result_t result = GLOBUS_SUCCESS; + DIR * secure_tmp_dir = NULL; + struct dirent * dir_entry = NULL; + static char * _function_name_ = + "globus_gsi_sysconfig_remove_all_proxy_files_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + secure_tmp_dir = globus_libc_opendir(DEFAULT_SECURE_TMP_DIR); + if(!secure_tmp_dir) + { + result = globus_error_put( + globus_error_wrap_errno_error( + GLOBUS_GSI_SYSCONFIG_MODULE, + errno, + GLOBUS_GSI_SYSCONFIG_ERROR_ERRNO, + __FILE__":%d:%s: Error opening directory: %s\n", + __LINE__, + _function_name_, + DEFAULT_SECURE_TMP_DIR)); + goto exit; + } + + while(globus_libc_readdir_r(secure_tmp_dir, &dir_entry) == 0 && + dir_entry != NULL) + { + if((default_filename && + !strcmp(dir_entry->d_name, default_filename)) || + !strncmp(dir_entry->d_name, + X509_UNIQUE_PROXY_FILE, + strlen(X509_UNIQUE_PROXY_FILE))) + { + full_filename = globus_gsi_cert_utils_create_string( + "%s%s%s", + DEFAULT_SECURE_TMP_DIR, + FILE_SEPERATOR, + dir_entry->d_name); + + if(stat(full_filename, &stx) == -1) + { + globus_free(dir_entry); + continue; + } + + RAND_add((void *) &stx, sizeof(stx), 2); + + if(stx.st_uid == getuid()) + { + static char msg[65] + = "DESTROYED BY GLOBUS\r\n"; + int f = open(full_filename, O_RDWR); + int size, rec, left; + if (f) + { + size = lseek(f, 0L, SEEK_END); + lseek(f, 0L, SEEK_SET); + if (size > 0) + { + rec = size / 64; + left = size - rec * 64; + while (rec) + { + write(f, msg, 64); + rec--; + } + if (left) + { + write(f, msg, left); + } + } + close(f); + } + remove(full_filename); + } + + free(full_filename); + } + globus_free(dir_entry); + } + + exit: + + if(secure_tmp_dir != NULL) + { + globus_libc_closedir(secure_tmp_dir); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +/** + * @name + * @ingroup + */ +globus_result_t +globus_gsi_sysconfig_is_superuser_unix( + int * is_superuser) +{ + static char * _function_name_ = + "globus_gsi_sysconfig_is_superuser_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if(getuid() == 0) + { + *is_superuser = 1; + } + else + { + *is_superuser = 0; + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return GLOBUS_SUCCESS; +} +/* @} */ + +globus_result_t +globus_gsi_sysconfig_get_gridmap_filename_unix( + char ** filename) +{ + char * home_dir = NULL; + char * gridmap_env = NULL; + char * gridmap_filename = NULL; + globus_gsi_statcheck_t status; + globus_result_t result = GLOBUS_SUCCESS; + static char * _function_name_ = + "globus_gsi_sysconfig_get_gridmap_filename_unix"; + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + if(((gridmap_env = (char *) getenv("GRIDMAP")) != NULL) || + ((gridmap_env = (char *) getenv("GLOBUSMAP")) != NULL) || + ((gridmap_env = (char *) getenv("globusmap")) != NULL) || + ((gridmap_env = (char *) getenv("GlobusMap")) != NULL)) + { + gridmap_filename = globus_gsi_cert_utils_create_string( + "%s", + gridmap_env); + if(!gridmap_filename) + { + GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + } + + if(!gridmap_filename) + { + if(getuid() == 0) + { + /* being run as root */ + + gridmap_filename = globus_gsi_cert_utils_create_string( + "%s", + DEFAULT_GRIDMAP); + if(!gridmap_filename) + { + GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + } + else + { + result = GLOBUS_GSI_SYSCONFIG_GET_HOME_DIR(&home_dir, &status); + if(result != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_GRIDMAP_FILENAME); + goto exit; + } + + if(home_dir && status == GLOBUS_FILE_DIR) + { + gridmap_filename = globus_gsi_cert_utils_create_string( + "%s%s%s", + home_dir, + FILE_SEPERATOR, + LOCAL_GRIDMAP); + if(!gridmap_filename) + { + GLOBUS_GSI_SYSTEM_CONFIG_MALLOC_ERROR; + goto exit; + } + } + } + } + + if(!gridmap_filename) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_GRIDMAP_FILENAME, + ("A valid gridmap file could not be found.")); + goto exit; + } + + *filename = gridmap_filename; + + exit: + + if(home_dir != NULL) + { + free(home_dir); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} +/* @} */ + +#endif /* done defining *_unix functions */ + +/** + * Get Unique Proxy Filename + * @ingroup globus_gsi_sysconfig + */ +/* @{ */ +/** + * Get a unique proxy cert filename. This is mostly used + * for delegated proxy credentials. Each filename returned + * is going to be unique for each time the function is called. + * + * @param unique_filename + * the unique filename for a delegated proxy cert + * + * @return + * GLOBUS_SUCCESS or an error object identifier + */ +globus_result_t +globus_gsi_sysconfig_get_unique_proxy_filename( + char ** unique_filename) +{ + char * default_unique_filename = NULL; + globus_result_t result; + char * proc_id_string = NULL; + char unique_tmp_name[L_tmpnam]; + char * unique_postfix = NULL; + static int i = 0; + globus_gsi_statcheck_t status; + static char * _function_name_ = + "globus_gsi_sysconfig_get_unique_proxy_filename"; + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_ENTER; + + memset(unique_tmp_name, 0, L_tmpnam); + + *unique_filename = NULL; + + result = GLOBUS_GSI_SYSCONFIG_GET_PROC_ID_STRING(&proc_id_string); + if(result != GLOBUS_SUCCESS) + { + proc_id_string = NULL; + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_DELEG_FILENAME); + goto done; + } + + if(tmpnam(unique_tmp_name) == NULL) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_DELEG_FILENAME, + ("Could not get a unique filename for the temporary proxy cert")); + goto done; + } + + unique_postfix = strrchr(unique_tmp_name, '/'); + ++unique_postfix; + + if((result = globus_i_gsi_sysconfig_create_key_string( + unique_filename, + & default_unique_filename, + & status, + "%s%s%s%s.%s.%d", + DEFAULT_SECURE_TMP_DIR, + FILE_SEPERATOR, + X509_UNIQUE_PROXY_FILE, + proc_id_string, + unique_postfix, + ++i)) != GLOBUS_SUCCESS) + { + GLOBUS_GSI_SYSCONFIG_ERROR_CHAIN_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_DELEG_FILENAME); + goto done; + } + + *unique_filename = default_unique_filename; + + if(!(*unique_filename)) + { + GLOBUS_GSI_SYSCONFIG_ERROR_RESULT( + result, + GLOBUS_GSI_SYSCONFIG_ERROR_GETTING_DELEG_FILENAME, + ("A file location for writing the unique proxy cert" + " could not be found in: %s\n", + default_unique_filename)); + + goto done; + } + + result = GLOBUS_SUCCESS; + + done: + + if(default_unique_filename && + (default_unique_filename != (*unique_filename))) + { + globus_libc_free(default_unique_filename); + } + + if(proc_id_string != NULL) + { + free(proc_id_string); + } + + GLOBUS_I_GSI_SYSCONFIG_DEBUG_EXIT; + return result; +} + +/* @} */ + +#endif diff --git a/main/src/ssh2rpd.cxx b/main/src/ssh2rpd.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a7b41bebe6b07b7ade300cb54c27785e6e0b26c1 --- /dev/null +++ b/main/src/ssh2rpd.cxx @@ -0,0 +1,106 @@ +// @(#)root/main:$Name: $:$Id: rmain.cxx,v 1.6 2002/05/10 08:30:06 brun Exp $ +// Author: Gerardo Ganis 1/7/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// ssh2rpd // +// // +// Small program to communicate successful result of sshd auth to the // +// relevant rootd and proofd daemons // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <syslog.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "Varargs.h" + + +const int kMAXPATHLEN = 1024; +char *gFileLog = 0; +int gDebug = 0; + +//______________________________________________________________________________ +void Info(const char *va_(fmt), ...) +{ + // Write info message to syslog. + + char buf[1024]; + va_list ap; + + va_start(ap,va_(fmt)); + vsprintf(buf, fmt, ap); + va_end(ap); + + if (gFileLog != 0 && strlen(gFileLog) > 0) { + FILE *fl= fopen(gFileLog,"a"); + fprintf(fl, "%s",buf); + fclose(fl); + } else { + syslog(LOG_INFO, buf); + } +} + +//______________________________________________________________________________ +int main(int argc, char **argv) +{ + char *Pipe = 0; int ProId=-1, RemId=-1; + + if (argc < 2) { + Info("ssh2rpd: argc=%d : at least one additional argument required - exit\n", argc); + exit(1); + } + + // Parse Arguments + gDebug = atoi(argv[1]); + if (argc > 2) Pipe = strdup(argv[2]); + if (argc > 3) ProId = atoi(argv[3]); + if (argc > 4) RemId = atoi(argv[4]); + if (argc > 5) gFileLog = strdup(argv[5]); + + + if (gDebug > 0) + Info("ssh2rpd: forked with args: %d %s %d %d '%s'\n",gDebug,Pipe,ProId,RemId,gFileLog); + + // Preparing socket connection + struct sockaddr_un servAddr; + servAddr.sun_family = AF_UNIX; + strcpy(servAddr.sun_path,Pipe); + int sd; + if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + Info("ssh2rpd: cannot open socket: exiting "); + exit(1); + } + // Connecting to socket + int rc; + if ((rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr))) < 0) { + Info("ssh2rpd: cannot connect socket: exiting (errno= %d)",errno); + exit(1); + } + + // Sending "OK" ... + char *okbuf = "OK"; + rc = send(sd, okbuf, strlen(okbuf), 0); + if (rc != (int)strlen(okbuf)) { + Info("ssh2rpd: sending might have been unsuccessful (bytes send: %d)",rc); + } + + if (Pipe != 0) free(Pipe); + if (gFileLog != 0) free(gFileLog); + + exit(0); +} diff --git a/net/inc/NetErrors.h b/net/inc/NetErrors.h new file mode 100644 index 0000000000000000000000000000000000000000..4dd55bf78e973bd2d33e8e0b76f2e1431cdab581 --- /dev/null +++ b/net/inc/NetErrors.h @@ -0,0 +1,58 @@ +// @(#)root/net:$Name:$:$Id:$ +// Author: Fons Rademakers 11/08/97 + +/************************************************************************* + * Copyright (C) 1995-2003, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_NetErrors +#define ROOT_NetErrors + + +////////////////////////////////////////////////////////////////////////// +// // +// NetErrors // +// // +// This header file defines error codes generated by rootd/proofd. // +// // +////////////////////////////////////////////////////////////////////////// + +#ifndef ROOT_Rtypes +#include "Rtypes.h" +#endif + +enum ERootdErrors { + kErrUndef, + kErrNoFile, + kErrBadFile, + kErrFileExists, + kErrNoAccess, + kErrFileOpen, + kErrFileWriteOpen, + kErrFileReadOpen, + kErrNoSpace, + kErrBadOp, + kErrBadMess, + kErrFilePut, + kErrFileGet, + kErrNoUser, + kErrNoAnon, + kErrBadUser, + kErrNoHome, + kErrNoPasswd, + kErrBadPasswd, + kErrNoSRP, + kErrFatal, + kErrRestartSeek, + kErrNotAllowed, + kErrConnectionRefused, + kErrAuthNotOK +}; + +R__EXTERN const char *gRootdErrStr[]; + +#endif diff --git a/net/inc/TAuthDetails.h b/net/inc/TAuthDetails.h new file mode 100644 index 0000000000000000000000000000000000000000..611be13b1e5a54af8771cc1dbe08812aa2183ff5 --- /dev/null +++ b/net/inc/TAuthDetails.h @@ -0,0 +1,80 @@ +// @(#)root/net:$Name: $:$Id: TInetAddress.h,v 1.4 2001/10/01 09:46:32 rdm Exp $ +// Author: G. Ganis 31/03/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TAuthDetails +#define ROOT_TAuthDetails + + +////////////////////////////////////////////////////////////////////////// +// // +// TAuthDetails // +// // +// Contains details about successful authentications // +// Used by THostAuth // +// // +////////////////////////////////////////////////////////////////////////// + +#ifndef ROOT_TObject +#include "TObject.h" +#endif +#ifndef ROOT_TString +#include "TString.h" +#endif +#ifndef ROOT_TAuthenticate +#include "TAuthenticate.h" +#endif + +class TAuthDetails : public TObject { + +public: + enum EService { kROOTD=1, kPROOFD }; + +private: + TString fHost; // Remote host and service (in form host:port:service) + TString fRealHost; // Remote host name + Int_t fPort; // Remote Port number + EService fService; // Remote Service flag + Int_t fMethod; // Authentication method used + Int_t fRemoteOffSet; // offset in remote host auth tab file (in bytes) + TString fRemoteLogin; // Remote login name (either auth user or one of the available anonymous) + TString fDetails; // Details for the auth process (user, principal, ... ) + Bool_t fReUse; // Determines if established authentication context should be reused + TString fToken; // Token identifying this authentication + Int_t fRSAKey; // Type of RSA key used + +public: + + TAuthDetails(const char *host, Int_t meth, Int_t offset, Bool_t reuse, + const char *details, const char *token, Int_t key, + const char *login = ""); + virtual ~TAuthDetails() { } + + const char *GetHost() const; + Int_t GetPort() const; + Int_t GetService() const; + Int_t GetMethod() const { return fMethod; } + const char *GetDetails() const { return fDetails; } + Bool_t GetReUse() const { return fReUse; } + const char *GetLogin() const { return fRemoteLogin; } + Int_t GetOffSet() const { return fRemoteOffSet; } + const char *GetToken() const { return fToken; } + Int_t GetRSAKey() const { return fRSAKey; } + + void SetOffSet(Int_t offset) { fRemoteOffSet = offset; } + void SetReUse(Bool_t reuse) { fReUse = reuse; } + void SetLogin(const char *login) { fRemoteLogin = login; } + + void Print(Option_t *option = "") const; + + ClassDef(TAuthDetails,0) // Class providing host specific authentication information +}; + +#endif diff --git a/net/inc/THostAuth.h b/net/inc/THostAuth.h new file mode 100644 index 0000000000000000000000000000000000000000..9c9be58280469883347588d88cdb506c71db5815 --- /dev/null +++ b/net/inc/THostAuth.h @@ -0,0 +1,81 @@ +// @(#)root/net:$Name: $:$Id: TInetAddress.h,v 1.4 2001/10/01 09:46:32 rdm Exp $ +// Author: G. Ganis 19/03/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_THostAuth +#define ROOT_THostAuth + + +////////////////////////////////////////////////////////////////////////// +// // +// THostAuth // +// // +// Contains details about host-specific authentication methods and the // +// result of their application // +// Used by TAuthenticate // +// // +////////////////////////////////////////////////////////////////////////// + +#ifndef ROOT_TObject +#include "TObject.h" +#endif +#ifndef ROOT_TString +#include "TString.h" +#endif +#ifndef ROOT_TList +#include "TList.h" +#endif + + +class THostAuth : public TObject { + +private: + TString fHost; // Host + TString fUser; // Username + Int_t fNumMethods; // Number of AuthMethods + Int_t *fMethods; // AuthMethods + TString *fDetails; // AuthDetails + + TList *fEstablished; // List of (TAuthDetails) established authentications + +public: + + THostAuth(); + THostAuth(const char *host, const char *user, Int_t nmeth, Int_t *authmeth, char **details); + THostAuth(const char *host, const char *user, Int_t authmeth, char *details); + virtual ~THostAuth(); + + Int_t NumMethods() const { return fNumMethods; } + Int_t GetMethods(Int_t meth) const { return fMethods[meth]; } + void AddMethod(Int_t level, char *details); + void RemoveMethod(Int_t level); + void ReOrder(Int_t nmet, Int_t *fmet); + void SetFirst(Int_t method); + void SetFirst(Int_t level, char *details); + + const char *GetDetails(Int_t level); + void SetDetails(Int_t level, char *details); + + const char *GetHost() const { return fHost; } + const char *GetUser() const { return fUser; } + + void SetHost(const char *host) { fHost = host; } + void SetUser(const char *user) { fUser = user; } + + TList *Established() const { return fEstablished; } + + void Print(Option_t *option = "") const; + void Print(const char *proc); + void PrintEstablished(); + + ClassDef(THostAuth,0) // Class providing host specific authentication information +}; + +#endif diff --git a/net/src/NetErrors.cxx b/net/src/NetErrors.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4903231d3070d463047ab8b58b5f2ed0d688ce6f --- /dev/null +++ b/net/src/NetErrors.cxx @@ -0,0 +1,50 @@ +// @(#)root/net:$Name:$:$Id:$ +// Author: Fons Rademakers 28/08/2003 + +/************************************************************************* + * Copyright (C) 1995-2003, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// NetErrors // +// // +// This file defines error strings mapped to the error codes generated // +// by rootd/proofd. // +// // +////////////////////////////////////////////////////////////////////////// + +#include "NetErrors.h" + +// Must match order of ERootdErrors enum in NetErrors.h +const char *gRootdErrStr[] = { + "undefined error", + "file not found", + "error in file name", + "file already exists", + "no access to file", + "error opening file", + "file already opened in read or write mode", + "file already opened in write mode", + "no more space on device", + "bad op code", + "bad message", + "error writing to file", + "error reading from file", + "no such user", + "remote not setup for anonymous access", + "illegal user name", + "can't cd to home directory", + "can't get passwd info", + "wrong passwd", + "no SRP support in remote daemon", + "fatal error", + "cannot seek to restart position", + "server does not accept the requested authentication method from this host or from user@host", + "server does not accept connection from this host: contact server administrator", + "authentication attempt unsuccessful" +}; diff --git a/net/src/TAuthDetails.cxx b/net/src/TAuthDetails.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a00f1fc3fe1e682bb5139bfa2d8549d8efbb3cc5 --- /dev/null +++ b/net/src/TAuthDetails.cxx @@ -0,0 +1,122 @@ +// @(#)root/net:$Name: $:$Id: TInetAddress.h,v 1.4 2001/10/01 09:46:32 rdm Exp $ +// Author: G. Ganis 19/03/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// TAuthDetails // +// // +// Contains details about successful authentications // +// Used by THostAuth // +// // +////////////////////////////////////////////////////////////////////////// + +#ifdef HAVE_CONFIG +#include "config.h" +#endif + +#include <stdlib.h> + +#include "TAuthDetails.h" + +ClassImp(TAuthDetails) + +//______________________________________________________________________________ +TAuthDetails::TAuthDetails(const char *host, Int_t meth, Int_t offset, + Bool_t reuse, const char *details, const char *token, + Int_t key, const char *login) +{ + // Create authdetails object. + + fHost = host; // contains also info about remote port and service + fPort = -2; + fService = (EService) 0; + fMethod = meth; + fRemoteOffSet = offset; + fRemoteLogin = login; + fDetails = details; + fReUse = reuse; + fToken = token; + fRSAKey = key; +} + +//______________________________________________________________________________ +const char *TAuthDetails::GetHost() const +{ + // Return remote host name. + + if (fRealHost == "") { + const_cast<TAuthDetails*>(this)->fRealHost = fHost; + if (fRealHost.Index(":") != kNPOS) + const_cast<TAuthDetails*>(this)->fRealHost.Remove(fRealHost.Index(":")); + } + + return fRealHost; +} + +//______________________________________________________________________________ +Int_t TAuthDetails::GetPort() const +{ + // Return remote port. Returns -1 if port not found. + + if (fPort == -2) { + Int_t f = fHost.First(':'); + Int_t l = fHost.Last(':'); + if (l == kNPOS || f == kNPOS || f == l) { + const_cast<TAuthDetails*>(this)->fPort = -1; + return fPort; + } + f++; + TString port = fHost(f, l-f); + const_cast<TAuthDetails*>(this)->fPort = atoi(port.Data()); + } + return fPort; +} + +//______________________________________________________________________________ +Int_t TAuthDetails::GetService() const +{ + // Return remote service flag, either kROOTD, kPROOFD or kUNKNOWN. + + if (fService == 0) { + Int_t f = fHost.First(':'); + Int_t l = fHost.Last(':'); + if (l == kNPOS || f == kNPOS || f == l) { + const_cast<TAuthDetails*>(this)->fService = (EService)-1; + return fService; + } + l++; + TString service = fHost(l, fHost.Length()-1); + const_cast<TAuthDetails*>(this)->fService = (EService) atoi(service.Data()); + } + return fService; +} + +//______________________________________________________________________________ +void TAuthDetails::Print(Option_t *opt) const +{ + // Print object content. If option is "e" print "established details. + + // Method names + const char *AuthMeth[kMAXSEC]= {"UsrPwd","SRP","Krb5","Globus","SSH","UidGid"}; + const char *Service[3]= {" ","rootd","proofd"}; + + Int_t srv = (GetService() > 0 && GetService() < 3) ? GetService() : 0; + + if (opt[0] == 'e') { + Info("PrintEstblshd","+ Method:%d (%s) OffSet:%d Login:%s ReUse:%d Port:%d Service:%s", + fMethod,AuthMeth[fMethod],fRemoteOffSet,fRemoteLogin.Data(),fReUse,GetPort(),Service[srv]); + Info("PrintEstblshd","+ Details:%s",fDetails.Data()); + } else { + Info("Print","+ Host:%s Port:%d Service:%s Method:%d (%s) OffSet:%d Login:%s ReUse:%d Details:%s", + GetHost(),GetPort(),Service[srv],fMethod,AuthMeth[fMethod],fRemoteOffSet,fRemoteLogin.Data(), + fReUse,fDetails.Data()); + } +} diff --git a/net/src/THostAuth.cxx b/net/src/THostAuth.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a595ab3e796ae7b68a75062d552c6327b02f1efc --- /dev/null +++ b/net/src/THostAuth.cxx @@ -0,0 +1,404 @@ +// @(#)root/net:$Name: $:$Id: TInetAddress.h,v 1.4 2001/10/01 09:46:32 rdm Exp $ +// Author: G. Ganis 19/03/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// THostAuth // +// // +// Contains details about host-specific authentication methods and the // +// result of their application. // +// Used by TAuthenticate. // +// // +////////////////////////////////////////////////////////////////////////// + +#ifdef HAVE_CONFIG +#include "config.h" +#endif + +#include "TSystem.h" +#include "THostAuth.h" +#include "TAuthDetails.h" + + +ClassImp(THostAuth) + +//______________________________________________________________________________ +THostAuth::THostAuth(): TObject() +{ + // Default constructor + + fHost = ""; + fUser = ""; + fNumMethods = 0; + fMethods = 0; + fDetails = 0; + fEstablished = 0; +} + +//______________________________________________________________________________ +THostAuth::THostAuth(const char *host, const char *user, Int_t nmeth, + Int_t *authmeth, char **details) +{ + // Create hostauth object. + + int i; + + fHost = host; + // Check and save the host FQDN ... + TInetAddress addr = gSystem->GetHostByName(fHost); + if (addr.IsValid()) { + fHost = addr.GetHostName(); + if (fHost == "UnNamedHost") + fHost = addr.GetHostAddress(); + } + fUser = user; + if (fUser == "") + fUser = gSystem->Getenv("USER"); + if (fUser == "") { + UserGroup_t *u = gSystem->GetUserInfo(); + if (u) + fUser = u->fUser; + delete u; + } + fNumMethods = nmeth; + fMethods = new Int_t[nmeth]; + if (authmeth != 0) { + for (i = 0; i < nmeth; i++) { fMethods[i] = authmeth[i]; } + } + fDetails = new TString[nmeth]; + if (details != 0) { + for (i = 0; i < nmeth; i++) { + if (details[i] != 0) fDetails[i] = details[i]; + } + } + fEstablished = new TList; +} + +//______________________________________________________________________________ +THostAuth::THostAuth(const char *host, const char *user, Int_t authmeth, + char *details) +{ + // Create hostauth object with one method only. + + fHost = host; + // Check and save the host FQDN ... + TInetAddress addr = gSystem->GetHostByName(fHost); + if (addr.IsValid()) { + fHost = addr.GetHostName(); + if (fHost == "UnNamedHost") + fHost = addr.GetHostAddress(); + } + fUser = user; + if (fUser == "") + fUser = gSystem->Getenv("USER"); + if (fUser == "") { + UserGroup_t *u = gSystem->GetUserInfo(); + if (u) + fUser = u->fUser; + delete u; + } + fNumMethods = 1; + fMethods = new Int_t[1]; + fMethods[0] = authmeth; + fDetails = new TString[1]; + if (details!=0) + fDetails[0] = details; + fEstablished = new TList; +} + +//______________________________________________________________________________ +void THostAuth::AddMethod(Int_t meth, char *details) +{ + // Add new method to the list. + + int i; + + // Save existing info + Int_t *tMethods = new Int_t[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { tMethods[i] = fMethods[i]; } + TString *tDetails = new TString[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { tDetails[i] = fDetails[i]; } + + // Resize arrays + delete [] fMethods; + delete [] fDetails; + fMethods = new Int_t[fNumMethods+1]; + for (i = 0; i < fNumMethods; i++) { fMethods[i] = tMethods[i]; } + fDetails = new TString[fNumMethods+1]; + for (i = 0; i < fNumMethods; i++) { fDetails[i] = tDetails[i]; } + + // delete temporary arrays + delete [] tMethods; + delete [] tDetails; + + // This is the new method + fMethods[fNumMethods] = meth; + fDetails[fNumMethods] = details; + + // Increment total number + fNumMethods++; + + if (gDebug > 3) Print(); +} + +//______________________________________________________________________________ +void THostAuth::RemoveMethod(Int_t meth) +{ + // Remove method 'meth' from the list, if there ... + + int i, k; + + // Make sure we are not empty + if (fNumMethods == 0) return; + + // Check if 'meth' is in the list + int j = -1; + for (i = 0; i < fNumMethods; i++) { if (fMethods[i] == meth) j = i; } + if (j == -1) return; + + // Save existing info + Int_t *tMethods = new Int_t[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { tMethods[i] = fMethods[i]; } + TString *tDetails = new TString[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { tDetails[i] = fDetails[i]; } + + // Resize arrays + delete [] fMethods; + delete [] fDetails; + fMethods = new Int_t[fNumMethods-1]; + fDetails = new TString[fNumMethods-1]; + k = 0; + for (i = 0; i < fNumMethods; i++) { + if (tMethods[i] != meth) { + fMethods[k] = tMethods[i]; + fDetails[k] = tDetails[i]; + k++; + } + } + // delete temporary arrays + delete [] tMethods; + delete [] tDetails; + + // Decrement total number + fNumMethods--; + + if (gDebug > 3) Print(); +} + +//______________________________________________________________________________ + THostAuth::~THostAuth() +{ + // The dtor. + + delete [] fMethods; + delete [] fDetails; + delete fEstablished; +} + +//______________________________________________________________________________ +const char *THostAuth::GetDetails(Int_t level) +{ + // Return authentication details for specified level + // or "" if the specified level does not exist for this host. + + int i; + for (i = 0; i < fNumMethods; i++) { + if (fMethods[i] == level) { + if (gDebug > 3) Info("GetDetails"," %d: returning fDetails[%d]: %s", level,i,fDetails[i].Data()); + return fDetails[i]; + } + } + static const char *empty = " "; + return empty; +} + +//______________________________________________________________________________ +void THostAuth::SetDetails(Int_t level, char *details) +{ + // Set authentication details for specified level. + + int i, jm=-1; + for (i = 0; i < fNumMethods; i++) { + if (fMethods[i] == level) { fDetails[i] = details; jm = i; break; } + } + // If not in the list, add new method ... + if (jm == -1) AddMethod(level, details); +} + +//______________________________________________________________________________ +void THostAuth::Print(Option_t *) const +{ + // Print object content. + + // Method names + const char *AuthMeth[kMAXSEC] = { "UsrPwd","SRP","Krb5","Globus","SSH","UidGid" }; + + Info("Print","+------------------------------------------------------------------+"); + Info("Print","+ Host:%s - User:%s - # of available methods:%d",fHost.Data(),fUser.Data(),fNumMethods); + int i = 0; + for (i = 0; i < fNumMethods; i++) { + Info("Print","+ Method: %d (%s) Details:%s",fMethods[i],AuthMeth[fMethods[i]],fDetails[i].Data()); + } + Info("Print","+------------------------------------------------------------------+"); +} + +//______________________________________________________________________________ +void THostAuth::Print(const char *proc) +{ + // Print object content. + + // Method names + const char *AuthMeth[kMAXSEC] = {"UsrPwd","SRP","Krb5","Globus","SSH","UidGid"}; + + Info("Print","%s +------------------------------------------------------------------+",proc); + Info("Print","%s + Host:%s - User:%s - # of available methods:%d",proc,fHost.Data(),fUser.Data(),fNumMethods); + int i = 0; + for (i = 0; i < fNumMethods; i++){ + Info("Print","%s + Method: %d (%s) Details:%s",proc,fMethods[i],AuthMeth[fMethods[i]],fDetails[i].Data()); + } + Info("Print","%s +------------------------------------------------------------------+",proc); +} + +//______________________________________________________________________________ +void THostAuth::PrintEstablished() +{ + // Print info about estalished authentication vis-a-vis of this Host. + + Info("PrintEstablished","+------------------------------------------------------------------------------+"); + Info("PrintEstablished","+ Host:%s - Number of Established Authentications: %d",fHost.Data(),fEstablished->GetSize()); + + // Check list + if (fEstablished->GetSize()>0) { + TIter next(fEstablished); + TAuthDetails *ai; + while ((ai = (TAuthDetails*) next())) + ai->Print("e"); + } + Info("PrintEstablished","+------------------------------------------------------------------------------+"); +} + +//______________________________________________________________________________ +void THostAuth::ReOrder(Int_t nmet, Int_t *fmet) +{ + // Set new order for existing methods according to fmet + int i, j; + + // Book new arrays + Int_t *tMethods = new Int_t[fNumMethods]; + TString *tDetails = new TString[fNumMethods]; + Int_t *flag = new Int_t[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { flag[i] = 0; } + + // Copy info in the new order + int k = 0; + for (j = 0; j < nmet; j++) { + int jm = -1; + for (i = 0; i < fNumMethods; i++) { + if (fmet[j] == fMethods[i] && flag[i] == 0) { + tMethods[k] = fMethods[i]; + tDetails[k] = fDetails[i]; + k++; + jm = i; + flag[i] = 1; + } + } + if (jm == -1) { + Warning("ReOrder","Enter: method %d not among the ones stored - ignore ",fmet[j]); + } + } + // Copying methods not listed ... if any + if (k < fNumMethods) { + for(i = 0; i < fNumMethods; i++){ + if (flag[i] == 0) { + tMethods[k] = fMethods[i]; + tDetails[k] = fDetails[i]; + k++; + flag[i] = 1; + } + } + } + + // Resize arrays + delete [] fMethods; + delete [] fDetails; + fMethods = new Int_t[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { fMethods[i] = tMethods[i]; } + fDetails = new TString[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { fDetails[i] = tDetails[i]; } + + // delete temporary arrays + delete [] tMethods; + delete [] tDetails; + + if (gDebug > 3) Print(); +} + +//______________________________________________________________________________ +void THostAuth::SetFirst(Int_t method) +{ + // Set 'method' to be the first used (if in the list ...). + + Int_t *meth = new Int_t[1], nmet = 1; + meth[0] = method; + + ReOrder(nmet,meth); + delete [] meth; + + if (gDebug > 3) Print(); +} + +//______________________________________________________________________________ +void THostAuth::SetFirst(Int_t level, char *details) +{ + // Set as first method 'level' with authentication 'details'. + // Faster then AddMethod(method,details)+SetFirst(method). + + int i; + + // Check first if the method is there already + for (i = 0; i < fNumMethods; i++) { + if (fMethods[i] == level) { + SetDetails(level, details); + SetFirst(level); + if (gDebug > 1) Print(); + return; + } + } + + // If not, added in first position ... Save existing info + Int_t *tMethods = new Int_t[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { tMethods[i] = fMethods[i]; } + TString *tDetails = new TString[fNumMethods]; + for (i = 0; i < fNumMethods; i++) { tDetails[i] = fDetails[i]; } + + // Resize arrays + delete [] fMethods; + delete [] fDetails; + fMethods = new Int_t[fNumMethods+1]; + fDetails = new TString[fNumMethods+1]; + + // This method first + fMethods[0] = level; + fDetails[0] = details; + + // The others ... + for (i = 0; i < fNumMethods; i++) { fMethods[i+1] = tMethods[i]; } + for (i = 0; i < fNumMethods; i++) { fDetails[i+1] = tDetails[i]; } + + // delete temporary arrays + delete [] tMethods; + delete [] tDetails; + + // Increment total number + fNumMethods++; + + if (gDebug > 3) Print(); +} diff --git a/rpdutils/Module.mk b/rpdutils/Module.mk new file mode 100644 index 0000000000000000000000000000000000000000..7ce78fe89ad798ade614263a5343b8b457789d6d --- /dev/null +++ b/rpdutils/Module.mk @@ -0,0 +1,83 @@ +# Module.mk for Rootd/Proofd authentication utilities +# Copyright (c) 2002 Rene Brun and Fons Rademakers +# +# Author: Gerardo Ganis, 7/4/2003 + +MODDIR := rpdutils +MODDIRS := $(MODDIR)/src +MODDIRI := $(MODDIR)/inc + +RPDUTILDIR := $(MODDIR) +RPDUTILDIRS := $(RPDUTILDIR)/src +RPDUTILDIRI := $(RPDUTILDIR)/inc + +##### libRPDUtil ##### +RPDUTILH := $(wildcard $(MODDIRI)/*.h) +RPDUTILS := $(wildcard $(MODDIRS)/*.cxx) +RPDUTILO := $(RPDUTILS:.cxx=.o) + +RPDUTILDEP := $(RPDUTILO:.o=.d) + +##### Flags used in rootd amd proofd Module.mk ##### +# use shadow passwords for authentication +ifneq ($(SHADOWFLAGS),) +SHADOWLIBS := $(SHADOWLIBDIR) $(SHADOWLIB) +endif + +# use AFS for authentication +ifneq ($(AFSLIB),) +AFSFLAGS := -DR__AFS +AFSLIBS := $(AFSLIBDIR) $(AFSLIB) +endif + +# use SRP for authentication +ifneq ($(SRPLIB),) +SRPFLAGS := -DR__SRP -I$(SRPINCDIR) +SRPLIBS := $(SRPLIBDIR) $(SRPLIB) +endif + +# use krb5 for authentication +ifneq ($(KRB5LIB),) +KRB5FLAGS := -DR__KRB5 -I$(KRB5INCDIR) +KRB5LIBS := $(KRB5LIBDIR) $(KRB5LIB) +endif + +# use Globus for authentication +ifneq ($(GLOBUSLIB),) +GLBSFLAGS := -DR__GLBS -I$(GLOBUSINCDIR) +GLBSLIBS := $(GLOBUSLIBDIR) $(GLOBUSLIB) +else +RPDUTILS := $(filter-out $(MODDIRS)/globus.cxx,$(RPDUTILS)) +RPDUTILO := $(filter-out $(MODDIRS)/globus.o,$(RPDUTILO)) +endif + +# Combined... +AUTHFLAGS := $(SHADOWFLAGS) $(AFSFLAGS) $(SRPFLAGS) $(KRB5FLAGS) \ + $(GLBSFLAGS) $(EXTRA_AUTHFLAGS) +AUTHLIBS := $(GLBSLIBS) $(SHADOWLIBS) $(AFSLIBS) $(SRPLIBS) $(KRB5LIBS) + +# used in the main Makefile +ALLHDRS += $(patsubst $(MODDIRI)/%.h,include/%.h,$(RPDUTILH)) + +# include all dependency files +INCLUDEFILES += $(RPDUTILDEP) + +##### local rules ##### +include/%.h: $(RPDUTILDIRI)/%.h + cp $< $@ + +all-rpdutils: $(RPDUTILO) + +clean-rpdutils: + @rm -f $(RPDUTILO) + +clean:: clean-rpdutils + +distclean-rpdutils: clean-rpdutils + @rm -f $(RPDUTILDEP) + +distclean:: distclean-rpdutils + +##### extra rules ###### +$(RPDUTILO): %.o: %.cxx + $(CXX) $(OPT) $(CXXFLAGS) $(AUTHFLAGS) -o $@ -c $< diff --git a/rpdutils/inc/rpderr.h b/rpdutils/inc/rpderr.h new file mode 100644 index 0000000000000000000000000000000000000000..51501cdf15c68168740537a3bbd8dcca6e4292cc --- /dev/null +++ b/rpdutils/inc/rpderr.h @@ -0,0 +1,31 @@ +// @(#)root/rpdutils:$Name: $:$Id: rootd.h,v 1.2 2001/02/22 09:43:25 rdm Exp $ +// Author: Fons Rademakers 11/08/97 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_rpderr +#define ROOT_rpderr + + +////////////////////////////////////////////////////////////////////////// +// // +// rpderr // +// // +// This header file defines error codes generated by rootd/proofd. // +// NB: In case of change update also strings in net/inc/ErrStr.h // +// // +////////////////////////////////////////////////////////////////////////// + +#ifndef ROOT_NetErrors +#include "NetErrors.h" +#endif + +typedef void (*ErrorHandler_t)(int level, const char *msg); + +#endif diff --git a/rpdutils/inc/rpdp.h b/rpdutils/inc/rpdp.h new file mode 100644 index 0000000000000000000000000000000000000000..cb1860158cb968f0d49a235765d39c06bd38d511 --- /dev/null +++ b/rpdutils/inc/rpdp.h @@ -0,0 +1,207 @@ +// @(#)root/rpdutils:$Name: $:$Id: rootd.h,v 1.2 2001/02/22 09:43:25 rdm Exp $ +// Author: Gerardo Ganis 7/4/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_rpdp +#define ROOT_rpdp + + +////////////////////////////////////////////////////////////////////////// +// // +// rpdp // +// // +// This header file contains private definitions and declarations // +// used by modules in rpdutils/src. // +// // +////////////////////////////////////////////////////////////////////////// + +#ifndef ROOT_VarArgs +#include "Varargs.h" +#endif +#ifndef ROOT_MessageTypes +#include "MessageTypes.h" +#endif +#ifndef ROOT_rpderr +#include "rpderr.h" +#endif + +typedef void (*SigPipe_t)(int); + +// Global consts +const int kMAXSEC = 6; +const int kMAXSECBUF = 2048; +const int kAUTH_REUSE_MSK = 0x1; +const int kAUTH_CRYPT_MSK = 0x2; +const int kMAXPATHLEN = 1024; + +// type of authentication method +enum ESecurity { kClear, kSRP, kKrb5, kGlobus, kSSH, kRfio }; + +// type of service +enum EService { kROOTD = 1, kPROOFD }; + +// Extern globals +namespace ROOT { + +extern int gAltSRP; +extern int gAnon; +extern int gAuth; +extern int gClientProtocol; +extern int gGlobus; +extern int gNumAllow; +extern int gNumLeft; +extern int gOffSet; +extern int gParallel; +extern int gRemPid; +extern int gReUseAllow; +extern int gReUseRequired; +extern int gSockFd; +extern int gSshdPort; + +extern char gAltSRPPass[kMAXPATHLEN]; +extern char gAnonUser[64]; +extern char gAuthAllow[kMAXPATHLEN]; +extern char gExecDir[kMAXPATHLEN]; // for use in rootd ... +extern char gFile[kMAXPATHLEN]; +extern char gFileLog[kMAXPATHLEN]; +extern char gHostCertConf[kMAXPATHLEN]; // Defines certificate location for globus authentication +extern char gOpenHost[256]; +extern char gService[10]; // "rootd" or "proofd", defined in proofd/rootd.cxx ... +extern char gTmpDir[kMAXPATHLEN]; // directory for temporary files (RW) + +extern char gUser[64]; +extern char gPasswd[64]; // only used for anonymous access + +extern SigPipe_t gSigPipeHook; + +extern double gBytesSent; +extern double gBytesRecv; + +// Error handlers prototypes ... +extern ErrorHandler_t gErrSys; +extern ErrorHandler_t gErrFatal; +extern ErrorHandler_t gErr; + +} // namespace ROOT + + +namespace ROOT { + +// error.cxx +int GetErrno(); +void ResetErrno(); +void ErrorInit(const char *ident); +void ErrorInfo(const char *va_(fmt), ...); +void Perror(char *buf); +void Error(ErrorHandler_t ErrHand,int code,const char *va_(fmt), ...); + +// net.cxx +int NetSendRaw(const void *buf, int len); +int NetRecvRaw(void *buf, int len); +int NetRecvRaw(int sock, void *buf, int len); +int NetSend(const void *buf, int len, EMessageTypes kind); +int NetSend(int code, EMessageTypes kind); +int NetSend(const char *msg, EMessageTypes kind = kMESS_STRING); +int NetSendAck(); +int NetSendError(ERootdErrors err); +int NetRecv(void *&buf, int &len, EMessageTypes &kind); +int NetRecv(char *msg, int len, EMessageTypes &kind); +int NetRecv(char *msg, int max); +int NetOpen(int inetdflag, EService service); +void NetClose(); +const char *NetRemoteHost(); +int NetInit(const char *service, int port1, int port2, int tcpwindowsize); +void NetInit(const char *service, int port, int tcpwindowsize); +void NetSetOptions(EService service, int sock, int tcpwindowsize); + +// netpar.cxx +int NetParOpen(int port, int size); +void NetParClose(); +int NetParSend(const void *buf, int len); +int NetParRecv(void *buf, int len); + +// daemon.cxx +void DaemonStart(int ignsigcld, int fdkeep, EService service); + +// rpdutils.cxx +int RpdGetAuthMethod(int kind); +int RpdUpdateAuthTab(int opt, char *line, char **token); +int RpdCleanupAuthTab(char *Host, int RemId); +int RpdCheckAuthTab(int Sec, char *User, char *Host,int RemId, int *OffSet); +bool RpdReUseAuth(const char *sstr, int kind); +int RpdCheckAuthAllow(int Sec, char *Host); +int RpdCheckHostWild(const char *Host, const char *host); +char *RpdGetIP(const char *host); +void RpdSendAuthList(); +void RpdCheckSession(int period); + +void RpdUser(const char *sstr); +void RpdSshAuth(const char *sstr); +void RpdKrb5Auth(const char *sstr); +void RpdSRPUser(const char *user); +int RpdCheckSpecialPass(const char *passwd); +void RpdPass(const char *pass); +void RpdGlobusAuth(const char *sstr); +void RpdRfioAuth(const char *sstr); +void RpdCleanup(const char *sstr); + +void RpdDefaultAuthAllow(); +int RpdCheckDaemon(const char *daemon); +int RpdCheckSshd(); +int RpdGuessClientProt(const char *buf, EMessageTypes kind); +char *RpdGetRandString(int Opt, int Len); +bool RpdCheckToken(char *tknin, char *tknref); + +void RpdSetAuthTabFile(char *AuthTabFile); +void RpdSetDebugFlag(int Debug); +void RpdSetRootLogFlag(int RootLog); + +int RpdGetRSAKeys(char *PubKey, int Opt); +void RpdSavePubKey(char *PubKey, int OffSet); +int RpdSecureSend(char *Str); +int RpdSecureRecv(char **Str); + + +} // namespace ROOT + +// Globus stuff ... +#ifdef R__GLBS +extern "C" { + #include <globus_gss_assist.h> + #include <openssl/x509.h> + #include <openssl/pem.h> + #include <sys/ipc.h> + #include <sys/shm.h> +} +// Globus Utility Function prototypes ... +namespace ROOT { + +void GlbsToolError(char *, int, int, int); +int GlbsToolCheckCert(char *, char **); +int GlbsToolCheckContext(int); +int GlbsToolStoreContext(gss_ctx_id_t, char *); +int GlbsToolStoreToShm(gss_buffer_t, int *); +char *GlbsToolExpand(char *); + +} // namespace ROOT + +#endif // Globus ... + +namespace ROOT { + +// Ssh Utility Function prototypes ... +int SshToolAllocateSocket(unsigned int, unsigned int, char **); +void SshToolDiscardSocket(char *, int); +int SshToolNotifyFailure(char *); +int SshToolGetAuth(int); + +} // namespace ROOT + +#endif diff --git a/rpdutils/src/daemon.cxx b/rpdutils/src/daemon.cxx new file mode 100644 index 0000000000000000000000000000000000000000..79abfeac15e3ac5c593efb3f24032ea532acc012 --- /dev/null +++ b/rpdutils/src/daemon.cxx @@ -0,0 +1,218 @@ +// @(#)root/rpdutils:$Name: $:$Id: daemon.cxx,v 1.5 2002/10/28 14:22:51 rdm Exp $ +// Author: Fons Rademakers 11/08/97 +// Modifified: Gerardo Ganis 8/04/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// DaemonStart // +// // +// Detach a daemon process from login session context. // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/param.h> +#if defined(__sun) || defined(__sgi) +# include <fcntl.h> +#endif + +#ifdef SIGTSTP +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#endif + +#ifndef NOFILE +# define NOFILE 0 +#endif + +#if defined(__hpux) +#define USE_SIGCHLD +#endif + +#if defined(__FreeBSD__) || defined(__APPLE__) +#define USE_SIGCHLD +#define SIGCLD SIGCHLD +#endif + +#if defined(linux) || defined(__hpux) || defined(__sun) || defined(__sgi) || \ + defined(_AIX) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(__MACH__) || (defined(__CYGWIN__) && defined(__GNUC__)) +#define USE_SETSID +#endif + + +#include "rpdp.h" + +namespace ROOT { + +extern int gDebug; + +#if defined(USE_SIGCHLD) +//______________________________________________________________________________ +static void SigChild(int) +{ + int pid; +#if defined(__hpux) || defined(__FreeBSD__) || defined(__APPLE__) + int status; +#else + union wait status; +#endif + + while ((pid = wait3(&status, WNOHANG, 0)) > 0) + ; +} +#endif + +//______________________________________________________________________________ +void DaemonStart(int ignsigcld, int fdkeep, EService service) +{ + // Detach a daemon process from login session context. + + // If we were started by init (process 1) from the /etc/inittab file + // there's no need to detach. + // This test is unreliable due to an unavoidable ambiguity + // if the process is started by some other process and orphaned + // (i.e. if the parent process terminates before we are started). + + int fd; + +#if !(defined(__CYGWIN__) && defined(__GNUC__)) + if (getppid() == 1) { + if (service == kROOTD) printf ("ROOTD_PID=%ld\n", (long) getpid()); + goto out; + } +#endif + + // Ignore the terminal stop signals (BSD). + +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif + + // If we were not started in the background, fork and let the parent + // exit. This also guarantees the first child is not a process + // group leader. + + int childpid; + if ((childpid = fork()) < 0) { + if (service == kROOTD) fprintf(stderr, "DaemonStart: can't fork first child\n"); + Error(gErrSys,kErrFatal, "DaemonStart: can't fork first child"); + } else if (childpid > 0) { +#ifdef SIGTSTP + if (service == kROOTD) printf("ROOTD_PID=%d\n", childpid); +#endif + exit(0); // parent + } else { + if (gDebug > 3) + ErrorInfo("DaemonStart: this is the child thread ... socket is: %d",fdkeep); + } + + // First child process... + + // Disassociate from controlling terminal and process group. + // Ensure the process can't reacquire a new controlling terminal. + +#ifdef SIGTSTP + +#ifdef USE_SETSID + if (setsid() == -1) { +#else + if (setpgrp(0, getpid()) == -1) { +#endif + if (service == kROOTD) fprintf(stderr, "DaemonStart: can't change process group\n"); + Error(gErrSys,kErrFatal, "DaemonStart: can't change process group"); + } + + if ((fd = open("/dev/tty", O_RDWR)) >= 0) { +#if !defined(__hpux) && !defined(__sun) && \ + !(defined(__CYGWIN__) && defined(__GNUC__)) + ioctl(fd, TIOCNOTTY, 0); // loose controlling tty +#endif + close(fd); + } + +#else + + if (setpgrp() == -1) { + if (service == kROOTD) fprintf(stderr, "DaemonStart: can't change process group\n"); + Error(gErrSys,kErrFatal, "DaemonStart: can't change process group"); + } + + + signal(SIGHUP, SIG_IGN); // immune from pgrp leader death + + if ((childpid = fork()) < 0) { + if (service == kROOTD) fprintf(stderr, "DaemonStart: can't fork second child\n"); + Error(gErrSys,kErrFatal, "DaemonStart: can't fork second child"); + } else if (childpid > 0) { + if (service == kROOTD) printf("ROOTD_PID=%d\n", childpid); + exit(0); // first child + } + +#endif +out: + // Close any open file descriptors + for (fd = 0; fd < NOFILE; fd++) { + int rc=-10; + if ((fd != fdkeep) || (service == kPROOFD)) rc = close(fd); + //if (rc==-1) ErrorInfo("DaemonStart: error closing file descriptor (rc=%d) %d: errno: %d ",rc,fd,(int)errno); + } + + ResetErrno(); // probably got set to EBADF from a close + + // Move current directory to root, make sure we aren't on a mounted + // file system. + + chdir("/"); + + // Clear any inherited file mode creation mask + + umask(0); + + // See if the caller isn't interested in the exit status of its + // children and doesn't want to have them become zombies and + // clog up the system. + // With SysV all we need to do is ignore the signal. + // With BSD, however, we have to catch each signal + // and execute the wait3() system call. + + if (ignsigcld) { +#ifdef USE_SIGCHLD + signal(SIGCLD, SigChild); +#else +#if defined(__alpha) && !defined(linux) + struct sigaction oldsigact, sigact; + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_NOCLDWAIT; + sigaction(SIGCHLD, &sigact, &oldsigact); +#elif defined(__sun) + sigignore(SIGCHLD); +#else + signal(SIGCLD, SIG_IGN); +#endif +#endif + } +} + +} // namespace ROOT + diff --git a/rpdutils/src/error.cxx b/rpdutils/src/error.cxx new file mode 100644 index 0000000000000000000000000000000000000000..376d8c7707ce366c2c67375975eae50fca16f3fc --- /dev/null +++ b/rpdutils/src/error.cxx @@ -0,0 +1,153 @@ +// @(#)root/rpdutils:$Name: $:$Id: daemon.cxx,v 1.5 2002/10/28 14:22:51 rdm Exp $ +// Author: Fons Rademakers 11/08/97 +// Modifified: Gerardo Ganis 8/04/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// error // +// // +// Set of error handling routines for daemon process. // +// Merging of rootd and proofd/src/error.cxx // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <syslog.h> +#include <errno.h> +#include <string.h> + +#if defined(hpux9) +extern "C" { + extern void openlog(const char *, int, int); + extern void syslog(int, const char *, ...); +} +#endif + +#ifdef __sun +# ifndef _REENTRANT +# if __SUNPRO_CC > 0x420 +# define GLOBAL_ERRNO +# endif +# endif +#endif + +#include "rpderr.h" +#include "rpdp.h" + +namespace ROOT { + +extern int gDebug; +extern int gRootLog; + +ErrorHandler_t gErrSys = 0; +ErrorHandler_t gErrFatal = 0; +ErrorHandler_t gErr = 0; + + +//______________________________________________________________________________ +int GetErrno() +{ +#ifdef GLOBAL_ERRNO + return ::errno; +#else + return errno; +#endif +} + +//______________________________________________________________________________ +void ResetErrno() +{ +#ifdef GLOBAL_ERRNO + ::errno = 0; +#else + errno = 0; +#endif +} + +//______________________________________________________________________________ +void ErrorInfo(const char *va_(fmt), ...) +{ + // Write info message to syslog. + + char buf[1024]; + va_list ap; + + va_start(ap,va_(fmt)); + vsprintf(buf, fmt, ap); + va_end(ap); + + if (gRootLog == 0) { + syslog(LOG_INFO, buf); + } else if (gRootLog == 1) { + fprintf(stderr, "%s\n",buf); + } else if (gRootLog == 2) { + if (strlen(gFileLog)>0) { + FILE *fl= fopen(gFileLog,"a"); + fprintf(fl, "%s\n",buf); + fclose(fl); + } + } +} + +//______________________________________________________________________________ +void ErrorInit(const char *ident) +{ + // Open syslog. + + openlog(ident, (LOG_PID | LOG_CONS), LOG_DAEMON); +} + +//______________________________________________________________________________ +void Perror(char *buf) +{ + // Return in buf the message belonging to errno. + + int len = strlen(buf); +#if (defined(__sun) && defined (__SVR4)) || defined (__linux) || \ + defined(_AIX) || defined(__MACH__) + sprintf(buf+len, " (%s)", strerror(GetErrno())); +#else + if (GetErrno() >= 0 && GetErrno() < sys_nerr) + sprintf(buf+len, " (%s)", sys_errlist[GetErrno()]); +#endif +} + +//______________________________________________________________________________ +void Error(ErrorHandler_t func, int code, const char *va_(fmt), ...) +{ + // Write fatal message to syslog and exit. + + char buf[1024]; + va_list ap; + + va_start(ap,va_(fmt)); + vsprintf(buf, fmt, ap); + va_end(ap); + + if (gRootLog == 0) { + syslog(LOG_ERR, buf); + } else if (gRootLog == 1) { + fprintf(stderr, "%s\n",buf); + } else if (gRootLog == 2) { + if (strlen(gFileLog)>0) { + FILE *fl= fopen(gFileLog,"a"); + fprintf(fl, "%s\n",buf); + fclose(fl); + } + } + + // Actions are defined by the specific error handler (see rootd.cxx and proofd.cxx) + if (func) (*func)(code,(const char *)buf); +} + +} // namespace ROOT diff --git a/rpdutils/src/globus.cxx b/rpdutils/src/globus.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c40e1ba4002557249a847fc301b417367d7a34ef --- /dev/null +++ b/rpdutils/src/globus.cxx @@ -0,0 +1,566 @@ +// @(#)root/rpdutils:$Name: $:$Id: daemon.cxx,v 1.5 2002/10/28 14:22:51 rdm Exp $ +// Author: Gerardo Ganis 7/4/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// globus // +// // +// Set of utilities for rootd/proofd daemon authentication via Globus // +// certificates. // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <pwd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> + +#include "rpdp.h" + + + +namespace ROOT { + +extern int gDebug; + +//--- Globals ------------------------------------------------------------------ +char gHostCertConf[kMAXPATHLEN] = "/etc/root/hostcert.conf"; // Defines certificate location for globus authentication + +//______________________________________________________________________________ +void GlbsToolError(char *mess, int majs, int mins, int toks) +{ + // Handle error ... + + char *GlbErr; + + if (!globus_gss_assist_display_status_str + (&GlbErr, mess, majs, mins, toks)) { + } else { + GlbErr = new char[kMAXPATHLEN]; + sprintf(GlbErr, "%s: error messaged not resolved ", mess); + } + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("Error: %s (majst=%d,minst=%d,tokst:%d)", GlbErr, majs, mins, + toks); + + delete [] GlbErr; +} + +//_________________________________________________________________________ +int GlbsToolCheckCert(char *ClientIssuerName, char **SubjName) +{ + // Load information about available certificates from user specified + // sources or from defaults. + // Returns number of potentially valid dir/cert/key triplets found. + + int retval = 1; + // char *hostcertconf_default = "globusauth/etc/hostcert.conf"; + // char *hostcertconf = 0; + char *certdir_default = "/etc/grid-security/certificates"; + char *hostcert_default = "/etc/grid-security/hostcert.pem"; + char *hostkey_default = "/etc/grid-security/hostkey.pem"; + char *gridmap_default = "/etc/grid-security/grid-mapfile"; + char dir_def[kMAXPATHLEN] = { 0 }, cert_def[kMAXPATHLEN] = { 0 }, + key_def[kMAXPATHLEN] = { 0 }, map_def[kMAXPATHLEN] = { 0 }; + char *dir_tmp = 0, *cert_tmp = 0, *key_tmp = 0, *map_tmp = 0; + bool CertFound = 0; + X509 *xcert = 0; + FILE *fcert = 0; + char *issuer_name = 0; + + if (gDebug > 2) + ErrorInfo("GlbsToolCheckCert: enter: %s", ClientIssuerName); + + if (gHostCertConf != 0) { + // The user/administrator provided a file ... check if it exists and can be read + FILE *fconf = 0; + if (!access(gHostCertConf, F_OK) && !access(gHostCertConf, R_OK) && + (fconf = fopen(gHostCertConf, "r")) != 0) { + char line[kMAXPATHLEN]; + if (gDebug > 2) + ErrorInfo("GlbsToolLoadCertInfo: reading host cert file %s", + gHostCertConf); + + // ... let's see what it's inside + while (fgets(line, sizeof(line), fconf)) { + if (line[0] == '#') + continue; // skip comment lines + int nw = + sscanf(line, "%s %s %s %s", dir_def, cert_def, key_def, + map_def); + + // allow for imcomplete lines ... completion with defaults ... + if (nw == 1) { + strcpy(cert_def, hostcert_default); + strcpy(key_def, hostkey_default); + strcpy(map_def, gridmap_default); + } else if (nw == 2) { + strcpy(key_def, hostkey_default); + strcpy(map_def, gridmap_default); + } else if (nw == 3) { + strcpy(map_def, gridmap_default); + } + // Expand for test if needed + dir_tmp = GlbsToolExpand(dir_def); + cert_tmp = GlbsToolExpand(cert_def); + key_tmp = GlbsToolExpand(key_def); + map_tmp = GlbsToolExpand(map_def); + if (gDebug > 2) + ErrorInfo + ("GlbsToolLoadCertInfo: testing host cert file map %s %s %s %s", + dir_tmp, cert_tmp, key_tmp, map_tmp); + + // check that the files exist and can be read + if (!access(dir_tmp, F_OK) && !access(dir_tmp, R_OK)) { + if (!access(cert_tmp, F_OK) && !access(cert_tmp, R_OK)) { + if (!access(key_tmp, F_OK) && !access(key_tmp, R_OK)) { + /// Load certificate + fcert = fopen(cert_tmp, "r"); + if (!PEM_read_X509(fcert, &xcert, 0, 0)) { + ErrorInfo + ("GlbsToolCheckCert: unable to load host certificate (%s)", + cert_tmp); + goto goout;; + } + // Get the issuer name + issuer_name = + X509_NAME_oneline(X509_get_issuer_name(xcert), 0, + 0); + if (strstr(issuer_name, ClientIssuerName) != 0) { + CertFound = 1; + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: Issuer Subject: %s matches", + issuer_name); + fclose(fconf); + goto found; + } + } else { + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: key file not existing or not readable (%s)", + key_tmp); + } + } else { + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: cert file not existing or not readable (%s)", + cert_tmp); + } + } else { + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: cert directory not existing or not readable (%s)", + dir_tmp); + } + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: read cert key map files: %s %s %s %s", + dir_tmp, cert_tmp, key_tmp, map_tmp); + } + fclose(fconf); + + } else { + if (gDebug > 2) + ErrorInfo + ("GlbsToolLoadCertInfo: host cert conf not existing or not readable (%s)", + gHostCertConf); + } + } else if (gDebug > 2) + ErrorInfo("GlbsToolCheckCert: HOSTCERTCONF undefined"); + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: Try to use env definitions or defaults ..."); + + // We have not found a goof one: try with these envs definitions or the defaults ... + if (getenv("X509_CERT_DIR") != 0) { + strcpy(dir_def, getenv("X509_CERT_DIR")); + } else + strcpy(dir_def, certdir_default); + if (getenv("X509_USER_CERT") != 0) { + strcpy(cert_def, getenv("X509_USER_CERT")); + } else + strcpy(cert_def, hostcert_default); + if (getenv("X509_USER_KEY") != 0) { + strcpy(key_def, getenv("X509_USER_KEY")); + } else + strcpy(key_def, hostkey_default); + if (getenv("GRIDMAP") != 0) { + strcpy(map_def, getenv("GRIDMAP")); + } else + strcpy(map_def, gridmap_default); + + // Expand for test if needed + dir_tmp = GlbsToolExpand(dir_def); + cert_tmp = GlbsToolExpand(cert_def); + key_tmp = GlbsToolExpand(key_def); + map_tmp = GlbsToolExpand(map_def); + + if (!access(dir_tmp, F_OK) && !access(dir_tmp, R_OK)) { + if (!access(cert_tmp, F_OK) && !access(cert_tmp, R_OK)) { + if (!access(key_tmp, F_OK) && !access(key_tmp, R_OK)) { + // Load certificate + fcert = fopen(cert_tmp, "r"); + if (!PEM_read_X509(fcert, &xcert, 0, 0)) { + ErrorInfo + ("GlbsToolCheckCert: unable to load host certificate (%s)", + cert_tmp); + goto goout; + } + // Get the issuer name + issuer_name = + X509_NAME_oneline(X509_get_issuer_name(xcert), 0, 0); + if (strstr(issuer_name, ClientIssuerName) != 0) { + CertFound = 1; + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckCert: Issuer Subject: %s matches", + issuer_name); + goto found; + } + } else { + ErrorInfo + ("GlbsToolCheckCert: default hostkey file not existing or not readable (%s)", + key_tmp); + goto goout; + } + } else { + ErrorInfo + ("GlbsToolCheckCert: default hostcert file not existing or not readable (%s)", + cert_tmp); + goto goout; + } + } else { + ErrorInfo + ("GlbsToolCheckCert: default cert dirrectory not existing or not readable (%s)", + dir_tmp); + goto goout; + } + + goout: + if (dir_tmp) + delete[]dir_tmp; + if (cert_tmp) + delete[]cert_tmp; + if (key_tmp) + delete[]key_tmp; + if (map_tmp) + delete[]map_tmp; + return 1; + + found: + if (CertFound) { + // Get the subject name + char *subject_name = + X509_NAME_oneline(X509_get_subject_name(xcert), 0, 0); + if (gDebug > 2) { + ErrorInfo("GlbsToolCheckCert: issuer: %s", issuer_name); + ErrorInfo("GlbsToolCheckCert: subject: %s", subject_name); + } + // Send it to the client ... + *SubjName = strdup(subject_name); + // Mission ok .. + retval = 0; + // free resources + free(issuer_name); + free(subject_name); + // We have found a valid one ... + fclose(fcert); + + // We set the relevant environment variables ... + if (setenv("X509_CERT_DIR", dir_def, 1)) { + ErrorInfo("GlbsToolCheckCert: unable to set X509_CERT_DIR "); + return 1; + } + if (setenv("X509_USER_CERT", cert_def, 1)) { + ErrorInfo("GlbsToolCheckCert: unable to set X509_USER_CERT "); + return 1; + } + if (setenv("X509_USER_KEY", key_def, 1)) { + ErrorInfo("GlbsToolCheckCert: unable to set X509_USER_KEY "); + return 1; + } + if (setenv("GRIDMAP", map_def, 1)) { + ErrorInfo("GlbsToolCheckCert: unable to set GRIDMAP "); + } + } + return retval; +} + + +//______________________________________________________________________________ +int GlbsToolCheckContext(int ShmId) +{ + // Checks validity of security context exported in shared memory + // segment SHmId. Returns 1 if valid, 0 othrwise. + + int retval = 0; + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; + OM_uint32 GssRetFlags = 0; + OM_uint32 GlbContLifeTime = 0; + int Dum1, Dum2; + gss_OID MechType; + gss_name_t *TargName = 0, *Name = 0; + + if (gDebug > 2) + ErrorInfo("GlbsToolCheckContext: checking contetx in shm : %d", + ShmId); + + // retrieve the context from shared memory ... + gss_buffer_t databuf = (gss_buffer_t) shmat(ShmId, 0, 0); + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckContext: retrieving info from shared memory: %d", + ShmId); + + // Import the security context ... + gss_buffer_t SecContExp = + (gss_buffer_t) new char[sizeof(gss_buffer_desc) + databuf->length]; + SecContExp->length = databuf->length; + SecContExp->value = + (void *) ((char *) SecContExp + sizeof(size_t) + sizeof(void *)); + void *dbufval = + (void *) ((char *) databuf + sizeof(size_t) + sizeof(void *)); + memmove(SecContExp->value, dbufval, SecContExp->length); + if ((MajStat = + gss_import_sec_context(&MinStat, SecContExp, + &context_handle)) != GSS_S_COMPLETE) { + GlbsToolError("GlbsToolCheckContext: gss_import_sec_context", + MajStat, MinStat, 0); + } else if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckContext: GlbsTool Sec Context successfully imported (0x%x)", + context_handle); + + delete[]SecContExp; + + // Detach from shared memory segment + int rc = shmdt((const void *) databuf); + if (rc != 0) { + ErrorInfo + ("GlbsToolCheckContext: unable to detach from shared memory segment %d (rc=%d)", + ShmId, rc); + } + // Check validity of the retrieved context ... + if (context_handle != 0 && context_handle != GSS_C_NO_CONTEXT) { + if ((MajStat = + gss_inquire_context(&MinStat, context_handle, Name, TargName, + &GlbContLifeTime, &MechType, &GssRetFlags, + &Dum1, &Dum2)) != GSS_S_COMPLETE) { + GlbsToolError("GlbsToolCheckContext: gss_inquire_context", + MajStat, MinStat, 0); + // mark segment for distruction + struct shmid_ds shm_ds; + if (!shmctl(ShmId, IPC_RMID, &shm_ds)) + ErrorInfo + ("GlbsToolCheckContext: unable to mark shared memory segment %d for desctruction", + ShmId); + } else { + if (gDebug > 2) + ErrorInfo + ("GlbsToolCheckContext: found valid context in shm %d", + ShmId); + retval = 1; + } + } + + return retval; +} + +//______________________________________________________________________________ +int GlbsToolStoreContext(gss_ctx_id_t context_handle, char *user) +{ + // Exports a security context for later use and stores in a shared memory + // segments. On success returns Id of the allocated shared memory segment, + // 0 otherwise. + + OM_uint32 MajStat; + OM_uint32 MinStat; + key_t shm_key = IPC_PRIVATE; + int shm_flg = 0777; + struct shmid_ds shm_ds; + + if (gDebug > 2) + ErrorInfo("GlbsToolStoreContext: Enter"); + + // First we have to prepare the export of the security context + gss_buffer_t SecContExp = new gss_buffer_desc; + if ((MajStat = + gss_export_sec_context(&MinStat, &context_handle, + SecContExp)) != GSS_S_COMPLETE) { + GlbsToolError("GlbsToolStoreContext: gss_export_sec_context", + MajStat, MinStat, 0); + delete SecContExp; + return 0; + } else if (gDebug > 2) + ErrorInfo + ("GlbsToolStoreContext: security context prepared for export"); + + // This is the size of the needed shared memory segment + int shm_size = sizeof(gss_buffer_desc) + SecContExp->length; + if (gDebug > 2) + ErrorInfo + ("GlbsToolStoreContext: needed shared memory segment sizes: %d", + shm_size); + + // Here we allocate the shared memory segment + int ShmId = shmget(shm_key, shm_size, shm_flg); + if (ShmId < 0) { + ErrorInfo + ("GlbsToolStoreContext: while allocating shared memory segment (rc=%d)", + ShmId); + delete SecContExp; + return 0; + } else if (gDebug > 2) + ErrorInfo + ("GlbsToolStoreContext: shared memory segment allocated (id=%d)", + ShmId); + + // Attach segment to address + gss_buffer_t databuf = (gss_buffer_t) shmat(ShmId, 0, 0); + if ((int) databuf < 0) { + ErrorInfo + ("GlbsToolStoreContext: while attaching to shared memory segment (rc=%d)", + (int) databuf); + delete SecContExp; + return 0; + } + databuf->length = SecContExp->length; + databuf->value = + (void *) ((char *) databuf + sizeof(size_t) + sizeof(void *)); + memmove(databuf->value, SecContExp->value, SecContExp->length); + + // Now we can detach from the shared memory segment ... and release memory we don't anylonger + int rc = 0; + if ((rc = shmdt((const void *) databuf)) != 0) { + ErrorInfo + ("GlbsToolStoreContext: unable to detach from shared memory segment (rc=%d)", + rc); + } + delete SecContExp; + + // We need to change the ownership of the shared memory segment used + // for credential export to allow proofserv to destroy it + if (shmctl(ShmId, IPC_STAT, &shm_ds) == -1) { + ErrorInfo + ("GlbsToolStoreContext: can't get info about shared memory segment %d", + ShmId); + return 0; + } + // Get info about user logging in + struct passwd *pw = getpwnam(user); + + // Give use ownership of the shared memory segment ... + shm_ds.shm_perm.uid = pw->pw_uid; + shm_ds.shm_perm.gid = pw->pw_gid; + if (shmctl(ShmId, IPC_SET, &shm_ds) == -1) { + ErrorInfo + ("GlbsToolStoreContext: can't change ownership of shared memory segment %d", + ShmId); + return 0; + } + // return shmid to rootd + return ShmId; +} + +//______________________________________________________________________________ +int GlbsToolStoreToShm(gss_buffer_t buffer, int *ShmId) +{ + // Creates a shm and stores buffer in it. + // Returns 0 on success (shm id in ShmId), >0 otherwise. + + key_t shm_key = IPC_PRIVATE; + int shm_flg = 0777; + + if (gDebug > 2) + ErrorInfo("GlbsToolStoreToShm: Enter: ShmId: %d", ShmId); + + // This is the size of the needed shared memory segment + int shm_size = sizeof(gss_buffer_desc) + buffer->length; + if (gDebug > 2) + ErrorInfo + ("GlbsToolStoreToShm: needed shared memory segment sizes: %d", + shm_size); + + // Here we allocate the shared memory segment + int lShmId = shmget(shm_key, shm_size, shm_flg); + if (lShmId < 0) { + ErrorInfo + ("GlbsToolStoreToShm: while allocating shared memory segment (rc=%d)", + lShmId); + return 1; + } else if (gDebug > 2) + ErrorInfo + ("GlbsToolStoreToShm: shared memory segment allocated (id=%d)", + lShmId); + + *ShmId = lShmId; + + // Attach segment to address + gss_buffer_t databuf = (gss_buffer_t) shmat(lShmId, 0, 0); + if ((int) databuf < 0) { + ErrorInfo + ("GlbsToolStoreToShm: while attaching to shared memory segment (rc=%d)", + (int) databuf); + return 2; + } + databuf->length = buffer->length; + databuf->value = + (void *) ((char *) databuf + sizeof(size_t) + sizeof(void *)); + memmove(databuf->value, buffer->value, buffer->length); + + // Now we can detach from the shared memory segment ... and release memory we don't anylonger + int rc = 0; + if ((rc = shmdt((const void *) databuf)) != 0) { + ErrorInfo + ("GlbsToolStoreToShm: unable to detach from shared memory segment (rc=%d)", + rc); + } + return 0; +} + + +//______________________________________________________________________________ +char *GlbsToolExpand(char *file) +{ + // Test is expansion is needed and return full path file name + // (expanded with $HOME). + // Returned string must be 'delete[] ed' by the caller. + + char *fret = 0; + + if (file) { + + if (file[0] == '/' || (!getenv("HOME"))) { + fret = new char[strlen(file) + 1]; + strcpy(fret, file); + } else { + fret = new char[strlen(file) + strlen(getenv("HOME")) + 2]; + if (file[0] == '~') { + sprintf(fret, "%s/%s", getenv("HOME"), file + 1); + } else { + sprintf(fret, "%s/%s", getenv("HOME"), file); + } + } + + } + return fret; +} + +} // namespace ROOT diff --git a/rpdutils/src/net.cxx b/rpdutils/src/net.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5b4442a6a9b0d23b27b347d868a840cf73894b48 --- /dev/null +++ b/rpdutils/src/net.cxx @@ -0,0 +1,600 @@ +// @(#)root/rpdutils:$Name: $:$Id: net.cxx,v 1.16 2002/10/28 14:22:51 rdm Exp $ +// Author: Fons Rademakers 12/08/97 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// net // +// // +// Set of network routines for rootd daemon process. // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> + +#if defined(linux) +# include <features.h> +# if __GNU_LIBRARY__ == 6 +# ifndef R__GLIBC +# define R__GLIBC +# endif +# endif +#endif +#if defined(__MACH__) && !defined(__APPLE__) +# define R__GLIBC +#endif + +#include "rpdp.h" +#include "rpderr.h" + +#if defined(_AIX) || (defined(__FreeBSD__) && !defined(__alpha__)) +# define USE_SIZE_T +#elif defined(R__GLIBC) || (defined(__FreeBSD__) && defined(__alpha__)) +# define USE_SOCKLEN_T +#endif + + +namespace ROOT { + +extern int gDebug; + +double gBytesSent = 0; +double gBytesRecv = 0; + +static char gOpenhost[256] = "????"; + +static int tcp_srv_sock; +static struct sockaddr_in tcp_srv_addr; +static struct sockaddr_in tcp_cli_addr; + +int gSockFd = -1; +char gFile[kMAXPATHLEN] = { 0 }; +SigPipe_t gSigPipeHook = 0; +extern int gParallel; + +//______________________________________________________________________________ +const char *NetRemoteHost() +{ + return gOpenhost; +} + +//______________________________________________________________________________ +static int Sendn(int sock, const void *buffer, int length) +{ + // Send exactly length bytes from buffer. + + if (sock < 0) return -1; + + int n, nsent = 0; + const char *buf = (const char *)buffer; + + for (n = 0; n < length; n += nsent) { + if ((nsent = send(sock, buf+n, length-n, 0)) <= 0) { + Error(gErrFatal, -1, "Sendn: error (sock: %d): errno: %d", + sock, GetErrno()); + return nsent; + } + } + + gBytesSent += n; + + return n; +} + +//______________________________________________________________________________ +static int Recvn(int sock, void *buffer, int length) +{ + // Receive exactly length bytes into buffer. Returns number of bytes + // received. Returns -1 in case of error. + + if (sock < 0) return -1; + + int n, nrecv = 0; + char *buf = (char *)buffer; + + for (n = 0; n < length; n += nrecv) { + while ((nrecv = recv(sock, buf+n, length-n, 0)) == -1 && GetErrno() == EINTR) + ResetErrno(); // probably a SIGCLD that was caught + if (nrecv < 0) { + Error(gErrFatal,-1,"Recvn: error (sock: %d): errno: %d",sock,GetErrno()); + return nrecv; + } else if (nrecv == 0) + break; // EOF + } + + gBytesRecv += n; + + return n; +} + +//______________________________________________________________________________ +int NetSendRaw(const void *buf, int len) +{ + // Send buffer of len bytes. + + if (gParallel > 0) { + + if (NetParSend(buf, len) != len) { + Error(gErrFatal,-1,"NetSendRaw: NetParSend error"); + } + + } else { + + if (gSockFd == -1) return -1; + if (Sendn(gSockFd, buf, len) != len) { + Error(gErrFatal,-1,"NetSendRaw: Sendn error"); + } + } + + return len; +} + +//______________________________________________________________________________ +int NetRecvRaw(void *buf, int len) +{ + // Receive a buffer of maximum len bytes. + + if (gParallel > 0) { + + if (NetParRecv(buf, len) != len) { + Error(gErrFatal,-1,"NetRecvRaw: NetParRecv error"); + } + + } else { + + if (gSockFd == -1) return -1; + if (Recvn(gSockFd, buf, len) < 0) { + Error(gErrFatal,-1,"NetRecvRaw: Recvn error (gSockFd: %d)",gSockFd); + } + } + + return len; +} + +//______________________________________________________________________________ +int NetRecvRaw(int sock, void *buf, int len) +{ + // Receive a buffer of maximum len bytes from generic socket sock. + + if (sock == -1) return -1; + + if (Recvn(sock, buf, len) < 0) { + Error(gErrFatal,-1,"NetRecvRaw: Recvn error (sock: %d, errno: %d)",sock,GetErrno()); + } + + return len; +} + +//______________________________________________________________________________ +int NetSend(const void *buf, int len, EMessageTypes kind) +{ + // Send buffer of len bytes. Message will be of type "kind". + + int hdr[2]; + int hlen = sizeof(int) + len; + hdr[0] = htonl(hlen); + hdr[1] = htonl(kind); + if (NetSendRaw(hdr, sizeof(hdr)) < 0) + return -1; + + return NetSendRaw(buf, len); +} + +//______________________________________________________________________________ +int NetSend(int code, EMessageTypes kind) +{ + // Send integer. Message will be of type "kind". + + int hdr[3]; + int hlen = sizeof(int) + sizeof(int); + hdr[0] = htonl(hlen); + hdr[1] = htonl(kind); + hdr[2] = htonl(code); + return NetSendRaw(hdr, sizeof(hdr)); +} + +//______________________________________________________________________________ +int NetSend(const char *msg, EMessageTypes kind) +{ + // Send a string. Message will be of type "kind". + + int len = 0; + + if (msg) + len = strlen(msg)+1; + + return NetSend(msg, len, kind); +} + +//______________________________________________________________________________ +int NetSendAck() +{ + return NetSend(0, kROOTD_ACK); +} + +//______________________________________________________________________________ +int NetSendError(ERootdErrors err) +{ + return NetSend(err, kROOTD_ERR); +} + +//______________________________________________________________________________ +int NetRecv(void *&buf, int &len, EMessageTypes &kind) +{ + // Receive a buffer. Returns the newly allocated buffer, the length + // of the buffer and message type in kind. + + int hdr[2]; + + if (NetRecvRaw(hdr, sizeof(hdr)) < 0) + return -1; + + len = ntohl(hdr[0]) - sizeof(int); + kind = (EMessageTypes) ntohl(hdr[1]); + if (len) { + buf = new char* [len]; + return NetRecvRaw(buf, len); + } + buf = 0; + return 0; +} + +//______________________________________________________________________________ +int NetRecv(char *msg, int len, EMessageTypes &kind) +{ + // Receive a string of maximum len length. Returns message type in kind. + // Return value is msg length. + + int mlen; + char *buf; + + if (NetRecv((void *&)buf, mlen, kind) < 0) + return -1; + + if (mlen == 0) { + msg[0] = 0; + return 0; + } else if (mlen > len) { + strncpy(msg, buf, len-1); + msg[len-1] = 0; + mlen = len; + } else + strcpy(msg, buf); + + delete [] buf; + + return mlen - 1; +} + +//______________________________________________________________________________ +int NetRecv(char *msg, int max) +{ + // Simulate TSocket::Recv(char *str, int max). + + EMessageTypes kind; + + return NetRecv((char *)msg, max, kind); +} + +//______________________________________________________________________________ +int NetOpen(int inetdflag, EService service) +{ + // Initialize the server's end. + // We are passed a flag that says whether or not we are started + // by a "master daemon" such as inetd. A master daemon will have + // already waited for a message to arrive for us and will have + // already set up the connection to the client. If we weren't + // started by a master daemon, then we must wait for a client's + // request to arrive. + +#if defined(USE_SIZE_T) + size_t clilen = sizeof(tcp_cli_addr); +#elif defined(USE_SOCKLEN_T) + socklen_t clilen = sizeof(tcp_cli_addr); +#else + int clilen = sizeof(tcp_cli_addr); +#endif + + if (inetdflag) { + + // When we're fired up by inetd, file decriptors 0, 1 and 2 + // are sockets to the client. + + gSockFd = 0; + if (!getpeername(gSockFd, (struct sockaddr *)&tcp_cli_addr, &clilen)) { + struct hostent *hp; + if ((hp = gethostbyaddr((const char *)&tcp_cli_addr.sin_addr, + sizeof(tcp_cli_addr.sin_addr), AF_INET))) + strcpy(gOpenhost, hp->h_name); + else { + struct in_addr *host_addr = (struct in_addr*)&tcp_cli_addr.sin_addr; + strcpy(gOpenhost, inet_ntoa(*host_addr)); + } + } + + // Notify, if requested ... + if (gDebug > 1) + ErrorInfo("NetOpen: fired by inetd: connection from host %s via socket %d", gOpenhost,gSockFd); + + // Set several general performance network options + NetSetOptions(service,gSockFd, 65535); + + return 0; + } + + // For the concurrent server that's not initiated by inetd, + // we have to wait for a connection request to arrive, then + // fork a child to handle the client's request. + // Beware that the accept() can be interrupted, such as by + // a previously spawned child process that has terminated + // (for which we caught the SIGCLD signal). + +again: + int newsock = accept(tcp_srv_sock, (struct sockaddr *)&tcp_cli_addr, &clilen); + if (newsock < 0) { + if (GetErrno() == EINTR) { + ResetErrno(); + goto again; // probably a SIGCLD that was caught + } + Error(gErrSys,kErrFatal, "NetOpen: accept error (errno: %d) ... socket %d",GetErrno(),tcp_srv_sock); + } + + struct hostent *hp; + if ((hp = gethostbyaddr((const char *)&tcp_cli_addr.sin_addr, + sizeof(tcp_cli_addr.sin_addr), AF_INET))) + strcpy(gOpenhost, hp->h_name); + else { + struct in_addr *host_addr = (struct in_addr*)&tcp_cli_addr.sin_addr; + strcpy(gOpenhost, inet_ntoa(*host_addr)); + } + + // Fork a child process to handle the client's request. + // The parent returns the child pid to the caller, which is + // probably a concurrent server that'll call us again, to wait + // for the next client request to this well-known port. + + int childpid; + if ((childpid = fork()) < 0) + Error(gErrSys,kErrFatal, "NetOpen: server can't fork"); + else if (childpid > 0) { // parent + close(newsock); + return childpid; + } + + // Child process continues here. + // First close the original socket so that the parent + // can accept any further requests that arrive there. + // Then set "gSockFd" in our process to be the descriptor + // that we are going to process. + + close(tcp_srv_sock); + + gSockFd = newsock; + + // Notify, if requested ... + if (gDebug > 1) + ErrorInfo("NetOpen: concurrent server: connection from host %s via socket %d", gOpenhost, gSockFd); + + return 0; +} + +//______________________________________________________________________________ +void NetClose() +{ + // Close the network connection. + + if (gParallel > 0) { + + NetParClose(); + + } else { + + close(gSockFd); + if (gDebug > 0) + ErrorInfo("NetClose: host = %s, fd = %d, file = %s", gOpenhost, gSockFd, + gFile); + gSockFd = -1; + } +} + +//______________________________________________________________________________ +int NetInit(const char *service, int port1, int port2, int tcpwindowsize) +{ + // Initialize the network connection for the server, when it has *not* + // been invoked by inetd. Used by rootd. + + // We weren't started by a master daemon. + // We have to create a socket ourselves and bind our well-known + // address to it. + + if (port1 <= 0) { + if (service) { + struct servent *sp; + if ((sp = getservbyname(service, "tcp")) == 0) { + fprintf(stderr, "NetInit: unknown service: %s/tcp\n", service); + Error(gErrFatal, kErrFatal, "NetInit: unknown service: %s/tcp", service); + } + port1 = ntohs(sp->s_port); + port2 += port1; // in this case, port2 is relative to service port + } else { + fprintf(stderr, "NetInit: must specify either service or port\n"); + Error(gErrFatal,kErrFatal, "NetInit: must specify either service or port"); + } + } + + // Create the socket and bind our local address so that any client can + // send to us. + + if ((tcp_srv_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "NetInit: can't create socket\n"); + Error(gErrSys,kErrFatal, "NetInit: can't create socket"); + } + + int val = 1; + if (setsockopt(tcp_srv_sock, SOL_SOCKET, SO_REUSEADDR, (char*) &val, + sizeof(val)) == -1) { + fprintf(stderr, "NetInit: can't set SO_REUSEADDR socket option\n"); + Error(gErrSys, kErrFatal, "NetInit: can't set SO_REUSEADDR socket option"); + } + + // Set several general performance network options + NetSetOptions(kROOTD,tcp_srv_sock, tcpwindowsize); + + memset(&tcp_srv_addr, 0, sizeof(tcp_srv_addr)); + tcp_srv_addr.sin_family = AF_INET; + tcp_srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + int port; + for (port= port1; port <= port2; port++) { + tcp_srv_addr.sin_port = htons(port); + if (bind(tcp_srv_sock, (struct sockaddr *) &tcp_srv_addr, + sizeof(tcp_srv_addr)) == 0) break; + } + + if (port > port2) { + fprintf(stderr, "NetInit: can't bind local address to ports %d-%d\n", port1, port2); + Error(gErrSys, kErrFatal, "NetInit: can't bind local address to ports %d-%d", port1, port2); + } + + printf("ROOTD_PORT=%d\n", port); + + // And set the listen parameter, telling the system that we're + // ready to accept incoming connection requests. + + // listen(tcp_srv_sock, 5); + if (listen(tcp_srv_sock, 5)==-1) { + ErrorInfo("NetInit: listen: error (errno: %d)",GetErrno()); + } + + if (gDebug > 0) + ErrorInfo("NetInit: socket %d listening on port %d", tcp_srv_sock, + ntohs(tcp_srv_addr.sin_port)); + + return tcp_srv_sock; +} + +//______________________________________________________________________________ +void NetInit(const char *service, int port, int tcpwindowsize) +{ + // Initialize the network connection for the server, when it has *not* + // been invoked by inetd. Used by proofd. + + // We weren't started by a master daemon. + // We have to create a socket ourselves and bind our well-known + // address to it. + + memset(&tcp_srv_addr, 0, sizeof(tcp_srv_addr)); + tcp_srv_addr.sin_family = AF_INET; + tcp_srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (service) { + + if (port > 0) + tcp_srv_addr.sin_port = htons(port); + else { + struct servent *sp; + if ((sp = getservbyname(service, "tcp")) == 0) + Error(gErrFatal,-1,"NetInit: unknown service: %s/tcp", service); + tcp_srv_addr.sin_port = sp->s_port; + } + + } else { + + if (port <= 0) + Error(gErrFatal,-1,"NetInit: must specify either service or port"); + tcp_srv_addr.sin_port = htons(port); + + } + + // Create the socket and bind our local address so that any client can + // send to us. + + if ((tcp_srv_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + Error(gErrSys,-1,"NetInit: can't create socket"); + + int val = 1; + if (setsockopt(tcp_srv_sock, SOL_SOCKET, SO_REUSEADDR, (char*) &val, + sizeof(val)) == -1) + Error(gErrSys,-1,"NetInit: can't set SO_REUSEADDR socket option"); + + // Set several general performance network options + NetSetOptions(kPROOFD,tcp_srv_sock, tcpwindowsize); + + if (bind(tcp_srv_sock, (struct sockaddr *) &tcp_srv_addr, + sizeof(tcp_srv_addr)) < 0) + Error(gErrSys,-1,"NetInit: can't bind local address (sock: %d) : errno: %d",tcp_srv_sock,GetErrno()); + + // And set the listen parameter, telling the system that we're + // ready to accept incoming connection requests. + + listen(tcp_srv_sock, 5); + + if (gDebug > 0) + ErrorInfo("NetInit: socket %d listening on port %d", tcp_srv_sock, + ntohs(tcp_srv_addr.sin_port)); +} + +//______________________________________________________________________________ +void NetSetOptions(EService serv, int sock, int tcpwindowsize) +{ + // Set some options for network socket. + + int val = 1; + + if (serv == kROOTD) { + if (!setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val))) { + if (gDebug > 0) ErrorInfo("NetSetOptions: set TCP_NODELAY"); + } + if (!setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&val, sizeof(val))) { + if (gDebug > 0) ErrorInfo("NetSetOptions: set SO_KEEPALIVE"); + if (gSigPipeHook != 0) signal(SIGPIPE, (*gSigPipeHook)); // handle SO_KEEPALIVE failure + } + } + + val = tcpwindowsize; + if (!setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, sizeof(val))) { + if (gDebug > 0) ErrorInfo("NetSetOptions: set SO_SNDBUF %d", val); + } + if (!setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, sizeof(val))) { + if (gDebug > 0) ErrorInfo("NetSetOptions: set SO_RCVBUF %d", val); + } + + if (gDebug > 0) { +#if defined(USE_SIZE_T) + size_t optlen = sizeof(val); +#elif defined(USE_SOCKLEN_T) + socklen_t optlen = sizeof(val); +#else + int optlen = sizeof(val); +#endif + if (serv == kROOTD) { + getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, &optlen); + ErrorInfo("NetSetOptions: get TCP_NODELAY: %d", val); + getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, &optlen); + ErrorInfo("NetSetOptions: get SO_KEEPALIVE: %d", val); + } + getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, &optlen); + ErrorInfo("NetSetOptions: get SO_SNDBUF: %d", val); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, &optlen); + ErrorInfo("NetSetOptions: get SO_RCVBUF: %d", val); + } +} + +} // namespace ROOT diff --git a/rpdutils/src/netpar.cxx b/rpdutils/src/netpar.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2dbf2bbeb7dde185ee331a4c2cabb28b096e376e --- /dev/null +++ b/rpdutils/src/netpar.cxx @@ -0,0 +1,280 @@ +// @(#)root/rpdutils:$Name: $:$Id: netpar.cxx,v 1.8 2003/04/06 21:30:13 rdm Exp $ +// Author: Fons Rademakers 06/02/2001 + +/************************************************************************* + * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// netpar // +// // +// Set of parallel network routines for rootd daemon process. To be // +// used when remote uses TPSocket to connect to rootd. // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <fcntl.h> +#include <errno.h> +#if defined(_AIX) +#include <strings.h> +#endif + +#if defined(linux) +# include <features.h> +# if __GNU_LIBRARY__ == 6 +# ifndef R__GLIBC +# define R__GLIBC +# endif +# endif +#endif +#if defined(__MACH__) && !defined(__APPLE__) +# define R__GLIBC +#endif + +#include "RConfig.h" +#include "rootdp.h" + +#if defined(_AIX) || (defined(__FreeBSD__) && !defined(__alpha__)) || \ + defined(R__SUNGCC3) +# define USE_SIZE_T +#elif defined(R__GLIBC) || (defined(__FreeBSD__) && defined(__alpha__)) +# define USE_SOCKLEN_T +#endif + +namespace ROOT { + +int gParallel = 0; + +extern int gDebug; + +static int gMaxFd; +static int *gPSockFd; +static int *gWriteBytesLeft; +static int *gReadBytesLeft; +static char **gWritePtr; +static char **gReadPtr; +static fd_set gFdSet; + + +//______________________________________________________________________________ +static void InitSelect(int nsock) +{ + // Setup select masks. + + FD_ZERO(&gFdSet); + gMaxFd = -1; + for (int i = 0; i < nsock; i++) { + FD_SET(gPSockFd[i], &gFdSet); + if (gPSockFd[i] > gMaxFd) + gMaxFd = gPSockFd[i]; + } +} + +//______________________________________________________________________________ +int NetParSend(const void *buf, int len) +{ + // Send buffer of specified length over the parallel sockets. + // Returns len in case of success and -1 in case of error. + + int i, alen = len, nsock = gParallel; + + // If data buffer is < 4K use only one socket + if (len < 4096) + nsock = 1; + + for (i = 0; i < nsock; i++) { + gWriteBytesLeft[i] = len/nsock; + gWritePtr[i] = (char *)buf + (i*gWriteBytesLeft[i]); + } + gWriteBytesLeft[i-1] += len%nsock; + + InitSelect(nsock); + + // Send the data on the parallel sockets + while (len > 0) { + + fd_set writeReady = gFdSet; + + int isel = select(gMaxFd+1, 0, &writeReady, 0, 0); + if (isel < 0) { + ErrorInfo("NetParSend: error on select"); + return -1; + } + + for (i = 0; i < nsock; i++) { + if (FD_ISSET(gPSockFd[i], &writeReady)) { + if (gWriteBytesLeft[i] > 0) { + int ilen; +again: + ilen = send(gPSockFd[i], gWritePtr[i], gWriteBytesLeft[i], 0); + if (ilen < 0) { + if (GetErrno() == EAGAIN) + goto again; + ErrorInfo("NetParSend: error sending for socket %d (%d)", + i, gPSockFd[i]); + return -1; + } + gWriteBytesLeft[i] -= ilen; + gWritePtr[i] += ilen; + len -= ilen; + } + } + } + } + + return alen; +} + +//______________________________________________________________________________ +int NetParRecv(void *buf, int len) +{ + // Receive buffer of specified length over parallel sockets. + // Returns len in case of success and -1 in case of error. + + int i, alen = len, nsock = gParallel; + + // If data buffer is < 4K use only one socket + if (len < 4096) + nsock = 1; + + for (i = 0; i < nsock; i++) { + gReadBytesLeft[i] = len/nsock; + gReadPtr[i] = (char *)buf + (i*gReadBytesLeft[i]); + } + gReadBytesLeft[i-1] += len%nsock; + + InitSelect(nsock); + + // Recieve the data on the parallel sockets + while (len > 0) { + + fd_set readReady = gFdSet; + + int isel = select(gMaxFd+1, &readReady, 0, 0, 0); + if (isel < 0) { + ErrorInfo("NetParRecv: error on select"); + return -1; + } + + for (i = 0; i < nsock; i++) { + if (FD_ISSET(gPSockFd[i], &readReady)) { + if (gReadBytesLeft[i] > 0) { + int ilen = recv(gPSockFd[i], gReadPtr[i], gReadBytesLeft[i], 0); + if (ilen < 0) { + ErrorInfo("NetParRecv: error receiving for socket %d (%d)", + i, gPSockFd[i]); + return -1; + } else if (ilen == 0) { + ErrorInfo("NetParRecv: EOF on socket %d (%d)", + i, gPSockFd[i]); + return 0; + } + gReadBytesLeft[i] -= ilen; + gReadPtr[i] += ilen; + len -= ilen; + } + } + } + } + + return alen; +} + +//______________________________________________________________________________ +int NetParOpen(int port, int size) +{ + // Open size parallel sockets back to client. Returns 0 in case of error, + // and number of parallel sockets in case of success. + + struct sockaddr_in remote_addr; + memset(&remote_addr, 0, sizeof(remote_addr)); + +#if defined(USE_SIZE_T) + size_t remlen = sizeof(remote_addr); +#elif defined(USE_SOCKLEN_T) + socklen_t remlen = sizeof(remote_addr); +#else + int remlen = sizeof(remote_addr); +#endif + + if (!getpeername(gSockFd, (struct sockaddr *)&remote_addr, &remlen)) { + remote_addr.sin_family = AF_INET; + remote_addr.sin_port = htons(port); + + gPSockFd = new int[size]; + + for (int i = 0; i < size; i++) { + if ((gPSockFd[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0) + Error(gErrSys, kErrFatal, "NetParOpen: can't create socket %d (%d)", + i, gPSockFd[i]); + + NetSetOptions(kROOTD, gPSockFd[i], 65535); + + if (connect(gPSockFd[i], (struct sockaddr *)&remote_addr, remlen) < 0) + Error(gErrSys, kErrFatal, "NetParOpen: can't connect socket %d (%d)", + i, gPSockFd[i]); + + // Set non-blocking + int val; + if ((val = fcntl(gPSockFd[i], F_GETFL, 0)) < 0) + Error(gErrSys, kErrFatal, "NetParOpen: can't get control flags"); + val |= O_NONBLOCK; + if (fcntl(gPSockFd[i], F_SETFL, val) < 0) + Error(gErrSys, kErrFatal, "NetParOpen: can't make socket non blocking"); + } + + gWriteBytesLeft = new int[size]; + gReadBytesLeft = new int[size]; + gWritePtr = new char*[size]; + gReadPtr = new char*[size]; + + // Close initial setup socket + NetClose(); + + gParallel = size; + + if (gDebug > 0) + ErrorInfo("NetParOpen: %d parallel connections established", size); + + } else + Error(gErrSys, kErrFatal, "NetParOpen: can't get peer name"); + + return gParallel; +} + +//______________________________________________________________________________ +void NetParClose() +{ + // Close parallel sockets. + + for (int i = 0; i < gParallel; i++) + close(gPSockFd[i]); + + delete [] gPSockFd; + delete [] gWriteBytesLeft; + delete [] gReadBytesLeft; + delete [] gWritePtr; + delete [] gReadPtr; + + gParallel = 0; + + if (gDebug > 0) + ErrorInfo("NetParClose: file = %s", gFile); +} + +} // namespace ROOT diff --git a/rpdutils/src/rpdutils.cxx b/rpdutils/src/rpdutils.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7fb87f7009351ef3b69ca35199640fc523f4a763 --- /dev/null +++ b/rpdutils/src/rpdutils.cxx @@ -0,0 +1,3435 @@ +// @(#)root/rpdutils:$Name: $:$Id: daemon.cxx,v 1.5 2002/10/28 14:22:51 rdm Exp $ +// Author: Gerardo Ganis 7/4/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// rpdutils // +// // +// Set of utilities for rootd/proofd daemon authentication. // +// // +////////////////////////////////////////////////////////////////////////// + +#include "config.h" + +#include <ctype.h> +#include <fcntl.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <errno.h> +#include <netdb.h> +#if defined(__alpha) && !defined(linux) +# ifdef _XOPEN_SOURCE +# if _XOPEN_SOURCE+0 > 0 +# define R__TRUE64 +# endif +# endif +#include <sys/mount.h> +#ifndef R__TRUE64 +extern "C" int fstatfs(int file_descriptor, struct statfs *buffer); +#endif +#elif defined(__APPLE__) +#include <sys/mount.h> +extern "C" int fstatfs(int file_descriptor, struct statfs *buffer); +#elif defined(linux) || defined(__hpux) +#include <sys/vfs.h> +#elif defined(__FreeBSD__) +#include <sys/param.h> +#include <sys/mount.h> +#else +#include <sys/statfs.h> +#endif + +#if defined(linux) || defined(__hpux) || defined(_AIX) || defined(__alpha) || \ + defined(__sun) || defined(__sgi) || defined(__FreeBSD__) || \ + defined(__APPLE__) +#define HAVE_MMAP +#endif + +#ifdef HAVE_MMAP +# include <sys/mman.h> +#ifndef MAP_FILE +#define MAP_FILE 0 /* compatability flag */ +#endif +#endif + +#if defined(linux) +# include <features.h> +# if __GNU_LIBRARY__ == 6 +# ifndef R__GLIBC +# define R__GLIBC +# endif +# endif +#endif +#if defined(__MACH__) && !defined(__APPLE__) +# define R__GLIBC +#endif + +#if (defined(__FreeBSD__) && (__FreeBSD__ < 4)) || defined(__APPLE__) +#include <sys/file.h> +#define lockf(fd, op, sz) flock((fd), (op)) +#ifndef F_LOCK +#define F_LOCK (LOCK_EX | LOCK_NB) +#endif +#ifndef F_ULOCK +#define F_ULOCK LOCK_UN +#endif +#endif + +#if defined(linux) || defined(__sun) || defined(__sgi) || \ + defined(_AIX) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(__MACH__) +#include <grp.h> +#include <sys/types.h> +#include <signal.h> +#endif + +#if defined(__sun) || defined(R__GLIBC) +#include <crypt.h> +#endif + +#if defined(__osf__) || defined(__sgi) +extern "C" char *crypt(const char *, const char *); +#endif + +#if defined(__alpha) && !defined(linux) && !defined(__FreeBSD__) +extern "C" int initgroups(const char *name, int basegid); +#endif + +#if defined(__sgi) && !defined(__GNUG__) && (SGI_REL<62) +extern "C" { + int seteuid(int euid); + int setegid(int egid); +} +#endif +#if defined(_AIX) +extern "C" { + //int initgroups(const char *name, int basegid); + int seteuid(uid_t euid); + int setegid(gid_t egid); +} +#endif +#if defined(__sun) +#ifndef R__SHADOWPW +#define R__SHADOWPW +#endif +#endif +#ifdef R__SHADOWPW +#include <shadow.h> +#endif +#ifdef R__AFS +//#include <afs/kautils.h> +#define KA_USERAUTH_VERSION 1 +#define KA_USERAUTH_DOSETPAG 0x10000 +#define NOPAG 0xffffffff +extern "C" int ka_UserAuthenticateGeneral(int, char *, char *, char *, + char *, int, int, int, char **); +#endif + +#ifdef R__SRP +extern "C" { +#include <t_pwd.h> +#include <t_server.h> +} +#endif +#ifdef R__KRB5 +extern "C" { +#include <com_err.h> +#include <krb5.h> + int krb5_net_write(krb5_context, int, const char *, int); +} +#include <string> +extern krb5_deltat krb5_clockskew; +#endif + +#include "rpdp.h" +extern "C" { +#include "rsadef.h" +#include "rsalib.h" +} +namespace ROOT {//--- Globals ------------------------------------------------------------------ +const char kRootdPass[] = ".rootdpass"; +const char kSRootdPass[] = ".srootdpass"; +const char kMethods[] = "usrpwd srp krb5 globus ssh uidgid"; + +// Statics +int gDebug = 0; +static int gAllowMeth[kMAXSEC]; +static int gTriedMeth[kMAXSEC]; +static int gHaveMeth[kMAXSEC]; +int gRootLog = 0; +static char gRpdAuthTab[kMAXPATHLEN] = { 0 }; // keeps track of authentication info + +// To control user access +char *gUserAllow[kMAXSEC] = { 0 }; +char *gUserIgnore[kMAXSEC] = { 0 }; +unsigned int gUserAlwLen[kMAXSEC] = { 0 }; +unsigned int gUserIgnLen[kMAXSEC] = { 0 }; + + +char gAltSRPPass[kMAXPATHLEN] = { 0 }; +char gAnonUser[64] = "rootd"; +char gAuthAllow[kMAXPATHLEN] = "/etc/root/rpdauth.allow"; // defines host-specific allowed methods for auth +char gExecDir[kMAXPATHLEN] = { 0 }; // needed to localize ssh2rpd +char gFileLog[kMAXPATHLEN] = { 0 }; +char gOpenHost[256] = "????"; // same length as in net.cxx ... +char gPasswd[64] = { 0 }; +char gService[10] = "????"; // "rootd" or "proofd", defined in proofd/rootd.cxx ... +char gTmpDir[kMAXPATHLEN] = { 0 }; // RW dir for temporary files +char gUser[64] = { 0 }; + +int gAltSRP = 0; +int gAnon = 0; +int gAuth = 0; +int gClientProtocol = 0; +int gGlobus = -1; +int gNumAllow = -1; +int gNumLeft = -1; +int gOffSet = -1; +int gRemPid = -1; +int gReUseAllow = 0x1F; // define methods for which previous auth can be reused +int gSshdPort = 22; + +// Globals of internal linkage +int gSec = -1; +int gRSAKey = 0; +rsa_NUMBER gRSA_n; +rsa_NUMBER gRSA_d; +char gPubKey[kMAXPATHLEN] = { 0 }; +int gMethInit = 0; +int gCryptRequired = -1; +int gReUseRequired = -1; + +} //namespace ROOT + +#ifdef R__KRB5 +krb5_keytab gKeytab = 0; // to allow specifying on the command line +krb5_context gKcontext; +#endif + +#ifdef R__GLBS +int gShmIdCred = -1; // global, to pass the shm ID to proofserv +gss_ctx_id_t GlbContextHandle = GSS_C_NO_CONTEXT; +#endif + +// Masks for authentication methods +const int kAUTH_CLR_MSK = 0x1; +const int kAUTH_SRP_MSK = 0x2; +const int kAUTH_KRB_MSK = 0x4; +const int kAUTH_GLB_MSK = 0x8; +const int kAUTH_SSH_MSK = 0x10; + +#define SafeDelete(p) { if (p) { delete p; p = 0; } } + +namespace ROOT { + +//______________________________________________________________________________ +void RpdSetDebugFlag(int Debug) +{ + // Change the value of the static gDebug to Debug. + + gDebug = Debug; + if (gDebug > 2) + ErrorInfo("RpdSetDebugFlag: gDebug set to %d", gDebug); +} + +//______________________________________________________________________________ +void RpdSetRootLogFlag(int RootLog) +{ + // Change the value of the static gRootLog to RootLog. + // Recognized values: + // 0 log to syslog (for root started daemons) + // 1 log to stderr ( for user started daemons) + + gRootLog = RootLog; + if (gDebug > 2) + ErrorInfo("RpdSetRootLogFlag: gRootLog set to %d", gRootLog); +} + +//______________________________________________________________________________ +void RpdSetAuthTabFile(char *AuthTabFile) +{ + // Change the value of the static gRpdAuthTab to AuthTabFile. + + strcpy(gRpdAuthTab, AuthTabFile); + if (gDebug > 2) + ErrorInfo("RpdSetAuthTabFile: gRpdAuthTab set to '%s'", AuthTabFile); +} + +//______________________________________________________________________________ +int RpdGetAuthMethod(int kind) +{ + int Meth = -1; + + if (kind == kROOTD_USER) + Meth = 0; + if (kind == kROOTD_SRPUSER) + Meth = 1; + if (kind == kROOTD_KRB5) + Meth = 2; + if (kind == kROOTD_GLOBUS) + Meth = 3; + if (kind == kROOTD_SSH) + Meth = 4; + if (kind == kROOTD_RFIO) + Meth = 5; + + return Meth; +} + +//______________________________________________________________________________ +int RpdUpdateAuthTab(int opt, char *line, char **token) +{ + // Update tab file. + // If opt=0 then eliminates all inactive entries, + // if opt=1 append 'line'. + // Returns offset for 'line' (opt=1) or -1 if any error occurs + // and token. + + int retval = -1; + int itab = 0; + char fbuf[kMAXPATHLEN]; + + if (gDebug > 2) + ErrorInfo("RpdUpdateAuthTab: analyzing: opt: %d, line: %s", opt, + line); + + if (opt == -1) { + if (!access(gRpdAuthTab, F_OK)) { + // Save the content ... + char *bak = new char[strlen(gRpdAuthTab) + 10]; + sprintf(bak, "%s.bak", gRpdAuthTab); + FILE *fbak = fopen(bak, "w"); + FILE *ftab = fopen(gRpdAuthTab, "r"); + char buf[kMAXPATHLEN]; + while (fgets(buf, sizeof(buf), ftab)) { + fprintf(fbak, "%s", buf); + } + fclose(fbak); + fclose(ftab); + // ... before deleting the original ... + unlink(gRpdAuthTab); + SafeDelete(bak); + } + return 0; + } else if (opt == 0) { + // Open file for update + itab = open(gRpdAuthTab, O_RDWR | O_CREAT, 0666); + if (itab == -1) { + ErrorInfo + ("RpdUpdateAuthTab: opt=%d: error opening %s (errno: %d)", + opt, gRpdAuthTab, GetErrno()); + return retval; + } + // override umask setting + fchmod(itab, 0666); + // lock tab file + if (lockf(itab, F_LOCK, (off_t) 1) == -1) { + ErrorInfo + ("RpdUpdateAuthTab: opt=%d: error locking %s (errno: %d)", + opt, gRpdAuthTab, GetErrno()); + close(itab); + return retval; + } + // File is open: get FILE descriptor + FILE *ftab = fdopen(itab, "a"); + // and set indicator to beginning + lseek(itab, 0, SEEK_SET); + + // Now scan over entries + int pr = 0, pw = 0; + int lsec, act; + char line[kMAXPATHLEN], dumm[kMAXPATHLEN]; + bool good = 0, fwr = 0; + + while (fgets(line, sizeof(line), ftab)) { + pr = lseek(itab, 0, SEEK_CUR); + sscanf(line, "%d %d %s", &lsec, &act, dumm); + good = (act == 1); + if (good) { + if (fwr) { + lseek(itab, pw, SEEK_SET); + sprintf(fbuf, "%s\n", line); + while (write(itab, fbuf, strlen(fbuf)) < 0 + && GetErrno() == EINTR) + ResetErrno(); + pw = lseek(itab, 0, SEEK_CUR); + lseek(itab, pr, SEEK_SET); + } else + pw = lseek(itab, 0, SEEK_CUR); + } else { + fwr = 1; + } + } + + // Truncate file to new length + ftruncate(itab, pw); + + retval = 0; + + } else if (opt == 1) { + // open file for append + if (gDebug > 2) + ErrorInfo("RpdUpdateAuthTab: opening file %s", gRpdAuthTab); + + if (access(gRpdAuthTab, F_OK)) { + itab = open(gRpdAuthTab, O_RDWR | O_CREAT, 0666); + if (itab == -1) { + ErrorInfo + ("RpdUpdateAuthTab: opt=%d: error opening %s (errno: %d)", + opt, gRpdAuthTab, GetErrno()); + return retval; + } + // override umask setting + fchmod(itab, 0666); + } else { + itab = open(gRpdAuthTab, O_RDWR); + } + if (itab == -1) { + ErrorInfo + ("RpdUpdateAuthTab: opt=%d: error opening or creating %s (errno: %d)", + opt, gRpdAuthTab, GetErrno()); + return retval; + } + // lock tab file + if (gDebug > 2) + ErrorInfo("RpdUpdateAuthTab: locking file %s", gRpdAuthTab); + if (lockf(itab, F_LOCK, (off_t) 1) == -1) { + ErrorInfo + ("RpdUpdateAuthTab: opt=%d: error locking %s (errno: %d)", + opt, gRpdAuthTab, GetErrno()); + close(itab); + return retval; + } + // saves offset + retval = lseek(itab, 0, SEEK_END); + if (gDebug > 2) + ErrorInfo("RpdUpdateAuthTab: offset is %d", retval); + + // Generate token + *token = RpdGetRandString(3, 8); // 8 crypt-like chras + char *CryptToken = crypt(*token, *token); + sprintf(fbuf, "%s %s\n", line, CryptToken); + if (gDebug > 2) + ErrorInfo("RpdUpdateAuthTab: token: '%s'", CryptToken); + + // adds line + while (write(itab, fbuf, strlen(fbuf)) < 0 && GetErrno() == EINTR) + ResetErrno(); + + } else { + ErrorInfo("RpdUpdateAuthTab: unrecognized option (opt= %d)", opt); + return retval; + } + + // unlock the file + lseek(itab, 0, SEEK_SET); + if (lockf(itab, F_ULOCK, (off_t) 1) == -1) { + ErrorInfo("RpdUpdateAuthTab: error unlocking %s", gRpdAuthTab); + } + // closing file ... + close(itab); + + return retval; +} + +//______________________________________________________________________________ +int RpdCleanupAuthTab(char *Host, int RemId) +{ + // Cleanup (set inactive) entries in tab file, + // if Host="all" or RemId=0 discard all entries. + // Return number of entries not cleaned properly ... + + int retval = 0; + + if (gDebug > 2) + ErrorInfo("RpdCleanupAuthTab: cleaning for Host: '%s', RemId:%d", + Host, RemId); + + // Open file for update + int itab = open(gRpdAuthTab, O_RDWR); + if (itab == -1) { + ErrorInfo("RpdCleanupAuthTab: error opening %s (errno: %d)", + gRpdAuthTab, GetErrno()); + // return retval; + return -1; + } + // lock tab file + if (lockf(itab, F_LOCK, (off_t) 1) == -1) { + ErrorInfo("RpdCleanupAuthTab: error locking %s (errno: %d)", + gRpdAuthTab, GetErrno()); + close(itab); + // return retval; + return -2; + } + // File is open: get FILE descriptor + FILE *ftab = fdopen(itab, "r+"); + + // Now scan over entries + int pr = 0, pw = 0; + int nw, lsec, act, parid, remid, pkey; + char line[kMAXPATHLEN], line1[kMAXPATHLEN], host[kMAXPATHLEN]; + char dumm[kMAXPATHLEN], user[kMAXPATHLEN]; +#ifdef R__GLBS + char subj[kMAXPATHLEN]; +#endif + + // and set indicator to beginning + pr = lseek(itab, 0, SEEK_SET); + pw = pr; + while (fgets(line, sizeof(line), ftab)) { + pr += strlen(line); + if (gDebug > 2) + ErrorInfo("RpdCleanupAuthTab: pr:%d pw:%d (line:%s)", pr, pw, + line); + + nw = sscanf(line, "%d %d %d %d %d %s %s %s", &lsec, &act, &pkey, + &parid, &remid, host, user, dumm); + if (nw > 5) { + if (!strcmp(Host, "all") || (RemId == 0) || + (!strcmp(Host, host) && (RemId == remid))) { + + // Delete Public Key file + char PubKeyFile[kMAXPATHLEN]; + sprintf(PubKeyFile, "%s/rpk_%d", gTmpDir, pw); + + if (gDebug > 0) { + struct stat st; + if (stat(PubKeyFile, &st) == 0) { + ErrorInfo("RpdCleanupAuthTab: file uid:%d gid:%d",st.st_uid,st.st_gid); + } + ErrorInfo("RpdCleanupAuthTab: proc uid:%d gid:%d",getuid(),getgid()); + } + + if (unlink(PubKeyFile) == -1) { + if (gDebug > 0) { + ErrorInfo + ("RpdCleanupAuthTab: problems unlinking pub key file '%s' (errno: %d)", + PubKeyFile,GetErrno()); + } + } + + if (act == 1) { + if (lsec == 3) { +#ifdef R__GLBS + int shmid; + nw = sscanf(line, "%d %d %d %d %d %s %s %d %s %s", &lsec, + &act, &pkey, &parid, &remid, host, user, + &shmid, subj, dumm); + struct shmid_ds shm_ds; + if (shmctl(shmid, IPC_RMID, &shm_ds) == -1) { + ErrorInfo + ("RpdCleanupAuthTab: unable to mark shared memory segment %d for desctruction (errno: %d)", + shmid, GetErrno()); + retval++; + } + sprintf(line1, "%d %d %d %d %d %s %s %d %s %s\n", lsec, + 0, pkey, parid, remid, host, user, shmid, subj, + dumm); +#else + ErrorInfo + ("RpdCleanupAuthTab: compiled without Globus support: you shouldn't have got here!"); + sprintf(line1, + "%d %d %d %d %d %s %s %s - WARNING: bad line\n", + lsec, 0, pkey, parid, remid, host, user, dumm); +#endif + } else { + sprintf(line1, "%d %d %d %d %d %s %s %s\n", lsec, 0, + pkey, parid, remid, host, user, dumm); + } + lseek(itab, pw, SEEK_SET); + while (write(itab, line1, strlen(line1)) < 0 + && GetErrno() == EINTR) + ResetErrno(); + lseek(itab, pr, SEEK_SET); + } + } + } + pw = pr; + } + + // unlock the file + lseek(itab, 0, SEEK_SET); + if (lockf(itab, F_ULOCK, (off_t) 1) == -1) { + ErrorInfo("RpdCleanupAuthTab: error unlocking %s", gRpdAuthTab); + } + // closing file ... + close(itab); + + return retval; +} + +//______________________________________________________________________________ +int RpdCheckAuthTab(int Sec, char *User, char *Host, int RemId, int *OffSet) +{ + // Check authentication entry in tab file. + + int retval = 0; + bool GoodOfs = 0; + int ofs = *OffSet >= 0 ? *OffSet : 0; + + if (gDebug > 2) + ErrorInfo("RpdCheckAuthTab: analyzing: %d %s %s %d %d", Sec, User, + Host, RemId, *OffSet); + + // First check if file exists and can be read + if (access(gRpdAuthTab, F_OK)) + return retval; + if (access(gRpdAuthTab, R_OK)) { + ErrorInfo("RpdCheckAuthTab: can't read file %s (errno: %d)", + gRpdAuthTab, GetErrno()); + return retval; + } + // Open file + int itab = open(gRpdAuthTab, O_RDWR); + if (itab == -1) { + ErrorInfo("RpdCheckAuthTab: error opening %s (errno: %d)", + gRpdAuthTab, GetErrno()); + return retval; + } + // lock tab file + if (lockf(itab, F_LOCK, (off_t) 1) == -1) { + ErrorInfo("RpdCheckAuthTab: error locking %s (errno: %d)", + gRpdAuthTab, GetErrno()); + close(itab); + return retval; + } + // File is open: set position at wanted location + FILE *ftab = fdopen(itab, "r+"); + fseek(ftab, ofs, SEEK_SET); + + // Now read the entry + char line[kMAXPATHLEN]; + fgets(line, sizeof(line), ftab); + + // and parse its content according to auth method + int lsec, act, parid, remid, shmid; + char host[kMAXPATHLEN], user[kMAXPATHLEN], subj[kMAXPATHLEN], + dumm[kMAXPATHLEN], tkn[20]; + int nw = + sscanf(line, "%d %d %d %d %d %s %s %s %s", &lsec, &act, &gRSAKey, + &parid, &remid, host, user, tkn, dumm); + if (gDebug > 2) + ErrorInfo("RpdCheckAuthTab: found line: %s", line); + if (nw > 5) { + if ((lsec == Sec)) { + if (lsec == 3) { + sscanf(line, "%d %d %d %d %d %s %s %d %s %s %s", &lsec, &act, + &gRSAKey, &parid, &remid, host, user, &shmid, subj, tkn, + dumm); + //if ((parid == getppid()) && (remid == RemId) + if ((remid == RemId) + && !strcmp(host, Host) && !strcmp(subj, User)) + GoodOfs = 1; + } else { + //if ((parid == getppid()) && (remid == RemId) && + if ((remid == RemId) && + !strcmp(host, Host) && !strcmp(user, User)) + GoodOfs = 1; + } + } + } + if (!GoodOfs) { + // Tab may have been cleaned in the meantime ... try a scan + fseek(ftab, 0, SEEK_SET); + ofs = ftell(ftab); + while (fgets(line, sizeof(line), ftab)) { + nw = sscanf(line, "%d %d %d %d %d %s %s %s %s", &lsec, &act, + &gRSAKey, &parid, &remid, host, user, tkn, dumm); + if (gDebug > 2) + ErrorInfo("RpdCheckAuthTab: found line: %s", line); + if (nw > 5) { + if (lsec == Sec) { + if (lsec == 3) { + sscanf(line, "%d %d %d %d %d %s %s %d %s %s %s", &lsec, + &act, &gRSAKey, &parid, &remid, host, user, + &shmid, subj, tkn, dumm); + //if ((parid == getppid()) && (remid == RemId) + if ((remid == RemId) + && !strcmp(host, Host) && !strcmp(subj, User)) { + GoodOfs = 1; + goto found; + } + } else { + //if ((parid == getppid()) && (remid == RemId) && + if ((remid == RemId) && + !strcmp(host, Host) && !strcmp(user, User)) { + GoodOfs = 1; + goto found; + } + } + } + } + } + } + + found: + if (gDebug > 2) + ErrorInfo("RpdCheckAuthTab: GoodOfs: %d", GoodOfs); + + // Rename the key file, if needed + if (*OffSet > 0 && *OffSet != ofs) { + char *OldName = new char[strlen(gTmpDir) + 50]; + char *NewName = new char[strlen(gTmpDir) + 50]; + //sprintf(OldName, "%s/rpk_%d_%d", gTmpDir, getppid(), *OffSet); + //sprintf(NewName, "%s/rpk_%d_%d", gTmpDir, getppid(), ofs); + sprintf(OldName, "%s/rpk_%d", gTmpDir, *OffSet); + sprintf(NewName, "%s/rpk_%d", gTmpDir, ofs); + if (rename(OldName, NewName) == -1) { + if (gDebug > 0) + ErrorInfo + ("RpdCheckAuthTab: Error renaming public key file (errno: %d)", + GetErrno()); + fseek(ftab, ofs, SEEK_SET); + // set entry inactive + if (Sec == 3) { +#ifdef R__GLBS + // kGlobus: + sprintf(line, "%d %d %d %d %d %s %s %d %s %s\n", lsec, 0, + gRSAKey, parid, remid, host, user, shmid, subj, + tkn); +#else + ErrorInfo + ("RpdCheckAuthTab: compiled without Globus support: you shouldn't have got here!"); +#endif + } else { + sprintf(line, "%d %d %d %d %d %s %s %s\n", lsec, 0, gRSAKey, + parid, remid, host, user, tkn); + } + while (write(itab, line, strlen(line)) < 0 + && GetErrno() == EINTR) + ResetErrno(); + } + SafeDelete(OldName); + SafeDelete(NewName); + } + + // Receive Token + char *token = 0; + if (gRSAKey > 0) { + // Get Public Key + char PubKeyFile[kMAXPATHLEN]; + sprintf(PubKeyFile, "%s/rpk_%d", gTmpDir, ofs); + if (gDebug > 2) + ErrorInfo("RpdCheckAuthTab: RSAKey ofs file: %d %d '%s' ", + gRSAKey, ofs, PubKeyFile); + if (RpdGetRSAKeys(PubKeyFile, 1) > 0) { + if (RpdSecureRecv(&token) == -1) { + ErrorInfo + ("RpdCheckAuthTab: problems secure-receiving token - may result in authentication failure "); + } + } + } else { + EMessageTypes kind; + int Tlen = 9; + token = new char[Tlen]; + NetRecv(token, Tlen, kind); + if (kind != kMESS_STRING) + ErrorInfo + ("RpdCheckAuthTab: got msg kind: %d instead of %d (kMESS_STRING)", + kind, kMESS_STRING); + // Invert Token + for (int i = 0; i < (int) strlen(token); i++) { + token[i] = ~token[i]; + } + } + + if (gDebug > 2) + ErrorInfo + ("RpdCheckAuthTab: received from client: token: '%s' ", + token); + + // Now check Token validity + if (GoodOfs && (act == 1) && token && RpdCheckToken(token, tkn)) { + + if (Sec == 3) { +#ifdef R__GLBS + // kGlobus: + if (GlbsToolCheckContext(shmid)) { + retval = 1; + strcpy(gUser, user); + } else { + // set entry inactive + fseek(ftab, ofs, SEEK_SET); + sprintf(line, "%d %d %d %d %d %s %s %d %s %s\n", lsec, 0, + gRSAKey, parid, remid, host, user, shmid, subj, + tkn); + while (write(itab, line, strlen(line)) < 0 + && GetErrno() == EINTR) + ResetErrno(); + } +#else + ErrorInfo + ("RpdCheckAuthTab: compiled without Globus support: you shouldn't have got here!"); +#endif + } else { + retval = 1; + } + + // Comunicate new offset to remote client + if (retval) *OffSet = ofs; + } + + // unlock the file + lseek(itab, 0, SEEK_SET); + if (lockf(itab, F_ULOCK, (off_t) 1) == -1) { + ErrorInfo("RpdCheckAuthTab: error unlocking %s", gRpdAuthTab); + } + // closing file ... + close(itab); + + return retval; +} + +//______________________________________________________________________________ +bool RpdCheckToken(char *token, char *tknref) +{ + // Check token validity. + + // Get rid of '\n' + char *s = strchr(token, '\n'); + if (s) + *s = 0; + s = strchr(tknref, '\n'); + if (s) + *s = 0; + + char *tkn_crypt = crypt(token, tknref); + + if (gDebug > 2) + ErrorInfo("RpdCheckToken: ref:'%s' crypt:'%s'", tknref, tkn_crypt); + + if (!strncmp(tkn_crypt, tknref, 13)) + return 1; + else + return 0; +} + +//______________________________________________________________________________ +bool RpdReUseAuth(const char *sstr, int kind) +{ + // Check the requiring subject has already authenticated during this session + // and its 'ticket' is still valid. + // Not implemented for SRP and Krb5 (yet). + + int Ulen, OffSet, Opt; + gOffSet = -1; + gAuth = 0; + + if (gDebug > 2) + ErrorInfo("RpdReUseAuth: analyzing: %s, %d", sstr, kind); + + char *User = new char[strlen(sstr)]; + char *Token = 0; + + // kClear + if (kind == kROOTD_USER) { + if (!(gReUseAllow & kAUTH_CLR_MSK)) + return 0; // re-authentication required by administrator + gSec = 0; + // Decode subject string + sscanf(sstr, "%d %d %d %d %s", &gRemPid, &OffSet, &Opt, &Ulen, User); + User[Ulen] = '\0'; + if ((gReUseRequired = (Opt & kAUTH_REUSE_MSK))) { + gOffSet = OffSet; + if (gRemPid > 0 && gOffSet > -1) { + gAuth = + RpdCheckAuthTab(gSec, User, gOpenHost, gRemPid, &gOffSet); + } + if ((gAuth == 1) && (OffSet != gOffSet)) + gAuth = 2; + // Fill gUser and free allocated memory + strcpy(gUser, User); + } + } + // kSRP + if (kind == kROOTD_SRPUSER) { + if (!(gReUseAllow & kAUTH_SRP_MSK)) + return 0; // re-authentication required by administrator + gSec = 1; + // Decode subject string + sscanf(sstr, "%d %d %d %d %s", &gRemPid, &OffSet, &Opt, &Ulen, User); + User[Ulen] = '\0'; + if ((gReUseRequired = (Opt & kAUTH_REUSE_MSK))) { + gOffSet = OffSet; + if (gRemPid > 0 && gOffSet > -1) { + gAuth = + RpdCheckAuthTab(gSec, User, gOpenHost, gRemPid, &gOffSet); + } + if ((gAuth == 1) && (OffSet != gOffSet)) + gAuth = 2; + // Fill gUser and free allocated memory + strcpy(gUser, User); + } + } + // kKrb5 + if (kind == kROOTD_KRB5) { + if (!(gReUseAllow & kAUTH_KRB_MSK)) + return 0; // re-authentication required by administrator + gSec = 2; + // Decode subject string + sscanf(sstr, "%d %d %d %d %s", &gRemPid, &OffSet, &Opt, &Ulen, User); + User[Ulen] = '\0'; + if ((gReUseRequired = (Opt & kAUTH_REUSE_MSK))) { + gOffSet = OffSet; + if (gRemPid > 0 && gOffSet > -1) { + gAuth = + RpdCheckAuthTab(gSec, User, gOpenHost, gRemPid, &gOffSet); + } + if ((gAuth == 1) && (OffSet != gOffSet)) + gAuth = 2; + // Fill gUser and free allocated memory + strcpy(gUser, User); + } + } + // kGlobus + if (kind == kROOTD_GLOBUS) { + if (!(gReUseAllow & kAUTH_GLB_MSK)) + return 0; // re-authentication required by administrator + gSec = 3; + // Decode subject string + int Slen; + sscanf(sstr, "%d %d %d %d %s", &gRemPid, &OffSet, &Opt, &Slen, User); + User[Slen] = '\0'; + if ((gReUseRequired = (Opt & kAUTH_REUSE_MSK))) { + gOffSet = OffSet; + if (gRemPid > 0 && gOffSet > -1) { + gAuth = + RpdCheckAuthTab(gSec, User, gOpenHost, gRemPid, &gOffSet); + } + if ((gAuth == 1) && (OffSet != gOffSet)) + gAuth = 2; + } + } + // kSSH + if (kind == kROOTD_SSH) { + if (!(gReUseAllow & kAUTH_SSH_MSK)) + return 0; // re-authentication required by administrator + gSec = 4; + // Decode subject string + char *Pipe = new char[strlen(sstr)]; + sscanf(sstr, "%d %d %d %s %d %s", &gRemPid, &OffSet, &Opt, Pipe, + &Ulen, User); + User[Ulen] = '\0'; + if ((gReUseRequired = (Opt & kAUTH_REUSE_MSK))) { + gOffSet = OffSet; + if (gRemPid > 0 && gOffSet > -1) { + gAuth = + RpdCheckAuthTab(gSec, User, gOpenHost, gRemPid, &gOffSet); + } + if ((gAuth == 1) && (OffSet != gOffSet)) + gAuth = 2; + // Fill gUser and free allocated memory + strcpy(gUser, User); + } + SafeDelete(Pipe); + } + + SafeDelete(User); + SafeDelete(Token); + + // Return value + if (gAuth >= 1) { + return 1; + } else { + return 0; + } +} + +//______________________________________________________________________________ +int RpdCheckAuthAllow(int Sec, char *Host) +{ + // Check if required auth method is allowed for 'Host'. + // If 'yes', returns 0, + // if 'no', returns 1, the number of allowed methods in NumAllow, and the + // codes of the allowed methods (in order of preference) in AllowMeth. + // Memory for AllowMeth must be allocated outside. + // Info read from /etc/root/rpdauth.allow. + + int retval = 1, found = 0; + + if (gDebug > 2) + ErrorInfo + ("RpdCheckAuthAllow: Checking file: %s for meth:%d host:%s (gNumAllow: %d)", + gAuthAllow, Sec, Host, gNumAllow); + + // Check if info already loaded (not first call ...) + if (gMethInit == 1) { + + // Look for the method in the allowed list and flag this method as tried, if found ... + int newtry = 0, i; + for (i = 0; i < gNumAllow; i++) { + if (gTriedMeth[i] == 0 && gAllowMeth[i] == Sec) { + newtry = 1; + gTriedMeth[i] = 1; + gNumLeft--; + } + } + if (newtry == 0) { + ErrorInfo + ("RpdCheckAuthAllow: new auth method proposed by client not in the list or already attempted"); + return retval; + } + retval = 0; + + } else { + // This is the first call ... check for host specific directives + gMethInit = 1; + + // First check if file exists and can be read + if (access(gAuthAllow, F_OK)) + return retval; + if (access(gAuthAllow, R_OK)) { + ErrorInfo("RpdCheckAuthAllow: can't read file %s (errno: %d)", + gAuthAllow, GetErrno()); + return retval; + } + // Open file + FILE *ftab = fopen(gAuthAllow, "r"); + if (ftab == 0) { + ErrorInfo("RpdCheckAuthAllow: error opening %s (errno: %d)", + gAuthAllow, GetErrno()); + return retval; + } + // Get IP of the host in form of a string + char *IP = RpdGetIP(Host); + if (gDebug > 2) + ErrorInfo("RpdCheckAuthAllow: Host: %s --> IP: %s", Host, IP); + + // Now read the entry + char line[kMAXPATHLEN], host[kMAXPATHLEN], rest[kMAXPATHLEN], + cmth[kMAXPATHLEN]; + int nmet = 0, mth[6] = { 0 }; + + int cont = 0, jm = -1; + while (fgets(line, sizeof(line), ftab)) { + int rc = 0, i; + if (line[0] == '#') + continue; // skip comment lines + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; // get rid of '\n', if any ... + // Analyze the line now ... + int nw = 0; + char *pstr = line; + // Check if a continuation line + if (cont == 1) { + cont = 0; + nw = sscanf(pstr, "%s", rest); + if (nw == 0) + continue; // empty line + } else { + jm = -1; + // Get 'host' first ... + nw = sscanf(pstr, "%s %s", host, rest); + if (nw < 2) + continue; // no method defined for this host + // pstr = strstr(line,rest); + pstr = line + strlen(host) + 1; + if (gDebug > 2) + ErrorInfo("RpdCheckAuthAllow: found host: %s ", host); + + if (strcmp(host, "default")) { + // now check validity of 'host' format + // Try first to understand whether it is an address or a name ... + int name = 0, namew = 0, nd = 0, nn = 0, nnmx = 0, nnmi = + strlen(host); + for (i = 0; i < (int) strlen(host); i++) { + if (host[i] == '.') { + nd++; + if (nn > nnmx) + nnmx = nn; + if (nn < nnmi) + nnmi = nn; + nn = 0; + continue; + } + int j = (int) host[i]; + if (j < 48 | j > 57) + name = 1; + if (host[i] == '*') { + namew = 1; + if (nd > 0) + goto next; + } + nn++; + } + // Act accordingly ... + if (name == 0) { + if (nd < 4) { + if (strlen(host) < 16) { + if (nnmx < 4) { + if (nd == 3 || host[strlen(host) - 1] == '.') { + char *sp = strstr(IP, host); + if (sp == 0 || sp != IP) + goto next; + + } + } + } + } + } else { + if (namew == 0) { + if (nd > 0) { + if (nd > 1 || nnmi > 0) { + char *sp = strstr(Host, host); + if (sp == 0 || sp != Host) + goto next; + } + } + } else { + if (RpdCheckHostWild(Host, host)) + goto next; + } + } + } else { + // This is a default entry: ignore it if a host-specific entry was already + // found, analyse it otherwise ... + if (found == 1) + goto next; + } + + if (rc != 0) + continue; // bad or unmatched name + + // Reset mth[kMAXSEC] + nmet = 0; + for (i = 0; i < kMAXSEC; i++) { + mth[i] = -1; + } + + } + + // We are at the end and there will be a continuation line ... + if ((int) rest[0] == 92) { + cont = 1; + continue; + } + + while (pstr != 0) { + int tmet = -1; + char *pd = 0, *pd2 = 0; + cmth[0] = '\0'; + rest[0] = '\0'; + nw = sscanf(pstr, "%s %s", cmth, rest); + if (!strcmp(cmth, "none")) { + nmet = 0; + goto nexti; + } + pd = strchr(cmth, ':'); + // Parse the method + char tmp[20]; + if (pd != 0) { + int mlen = pd - cmth; + strncpy(tmp, cmth, mlen); + tmp[mlen] = '\0'; + } else { + strcpy(tmp, cmth); + } + if (strlen(tmp) > 1) { + // Method passed as string: translate it to number + char *pmet = strstr(kMethods, tmp); + if (pmet != 0) { + tmet = ((int) (pmet - kMethods)) / 7; + } else { + ErrorInfo + ("RpdCheckAuthAllow: unknown methods %s - ignore", + tmp); + goto nexti; + } + } else { + tmet = atoi(tmp); + } + jm = -1; + if (gDebug > 2) + ErrorInfo("RpdCheckAuthAllow: found method %d (have?:%d)", + tmet, gHaveMeth[tmet]); + if (tmet >= 0 && tmet <= kMAXSEC) { + if (gHaveMeth[tmet] == 1) { + int i; + for (i = 0; i < nmet; i++) { + if (mth[i] == tmet) { + jm = i; + } + } + } else + goto nexti; + } else + goto nexti; + if (jm == -1) { + // New method ... + mth[nmet] = tmet; + jm = nmet; + nmet++; + } + // Now parse users list, if any ... + while (pd != 0 && (int) (pd[1]) != 32) { + pd2 = strchr(pd + 1, ':'); + if (pd[1] == '-') { + pd += 2; + // Ignore + if (gUserIgnore[mth[jm]] == 0) { + gUserIgnLen[mth[jm]] = kMAXPATHLEN; + gUserIgnore[mth[jm]] = new char[gUserIgnLen[mth[jm]]]; + gUserIgnore[mth[jm]][0] = '\0'; + } + if (strlen(gUserIgnore[mth[jm]]) > + (gUserIgnLen[mth[jm]] - 10)) { + char *UItmp = strdup(gUserIgnore[mth[jm]]); + free(gUserIgnore[mth[jm]]); + gUserIgnLen[mth[jm]] += kMAXPATHLEN; + gUserIgnore[mth[jm]] = new char[gUserIgnLen[mth[jm]]]; + strcpy(gUserIgnore[mth[jm]], UItmp); + free(UItmp); + } + char usr[256]; + if (pd2 != 0) { + int ulen = pd2 - pd; + strncpy(usr, pd, ulen); + usr[ulen] = '\0'; + } else { + strcpy(usr, pd); + } + struct passwd *pw = getpwnam(usr); + if (pw != 0) + sprintf(gUserIgnore[mth[jm]], "%s %d", + gUserIgnore[mth[jm]], pw->pw_uid); + } else { + pd += 1; + if (pd[1] == '+') + pd += 1; + // Keep + if (gUserAllow[mth[jm]] == 0) { + gUserAlwLen[mth[jm]] = kMAXPATHLEN; + gUserAllow[mth[jm]] = new char[gUserAlwLen[mth[jm]]]; + gUserAllow[mth[jm]][0] = '\0'; + } + if (strlen(gUserAllow[mth[jm]]) > + (gUserAlwLen[mth[jm]] - 10)) { + char *UItmp = strdup(gUserAllow[mth[jm]]); + free(gUserAllow[mth[jm]]); + gUserAlwLen[mth[jm]] += kMAXPATHLEN; + gUserAllow[mth[jm]] = new char[gUserAlwLen[mth[jm]]]; + strcpy(gUserAllow[mth[jm]], UItmp); + free(UItmp); + } + char usr[256]; + if (pd2 != 0) { + int ulen = pd2 - pd; + strncpy(usr, pd, ulen); + usr[ulen] = '\0'; + } else { + strcpy(usr, pd); + } + struct passwd *pw = getpwnam(usr); + if (pw != 0) + sprintf(gUserAllow[mth[jm]], "%s %d", + gUserAllow[mth[jm]], pw->pw_uid); + } + pd = pd2; + } + // Get next item + nexti: + if (nw > 1 && (int) rest[0] != 92) { + pstr = strstr(pstr, rest); + } else { + if ((int) rest[0] == 92) + cont = 1; + pstr = 0; + } + } + if (gDebug > 2) { + ErrorInfo("RpdCheckAuthAllow: for host %s found %d methods", + host, nmet); + ErrorInfo("RpdCheckAuthAllow: %d %d %d %d %d %d", mth[0], + mth[1], mth[2], mth[3], mth[4], mth[5]); + } + // Found new entry matching: superseed previous result + found = 1; + retval = 1; + gNumAllow = gNumLeft = nmet; + for (i = 0; i < kMAXSEC; i++) { + gAllowMeth[i] = -1; + gTriedMeth[i] = 0; + if (i < gNumAllow) { + gAllowMeth[i] = mth[i]; + if (Sec == mth[i]) { + retval = 0; + gNumLeft--; + gTriedMeth[i] = 1; + } + } + } + next: + continue; + } + + // closing file ... + fclose(ftab); + + // Free allocated memory + SafeDelete(IP); + + // Use defaults if nothing found + if (!found) { + int i; + for (i = 0; i < gNumAllow; i++) { + if (Sec == gAllowMeth[i]) { + retval = 0; + gNumLeft--; + gTriedMeth[i] = 1; + } + } + + } + } + if (gDebug > 2) { + ErrorInfo + ("RpdCheckAuthAllow: returning: %d (gNumAllow: %d, gNumLeft:%d)", + retval, gNumAllow, gNumLeft); + int i, jm; + for (i = 0; i < kMAXSEC; i++) { + jm = gAllowMeth[i]; + if (gUserAlwLen[jm] > 0) + ErrorInfo("RpdCheckAuthAllow: users allowed for method %d: %s", + jm, gUserAllow[jm]); + } + for (i = 0; i < kMAXSEC; i++) { + jm = gAllowMeth[i]; + if (gUserIgnLen[jm] > 0) + ErrorInfo("RpdCheckAuthAllow: users ignored for method %d: %s", + jm, gUserIgnore[jm]); + } + } + + return retval; +} + +//______________________________________________________________________________ +int RpdCheckHostWild(const char *Host, const char *host) +{ + // Checks if 'host' is compatible with 'Host' taking into account + // wild cards in the machine name (first field of FQDN) ... + // Returns 0 if successful, 1 otherwise ... + + int rc = 0; + char *fH, *sH, *dum, *sp, *k; + int i, j, lmax; + + if (gDebug > 2) + ErrorInfo("RpdCheckHostWild: analyzing Host:%s host:%s", Host, host); + + // Max length for dinamic allocation + lmax = strlen(Host) > strlen(host) ? strlen(Host) : strlen(host); + + // allocate + fH = new char[lmax]; + sH = new char[lmax]; + dum = new char[lmax]; + + // Determine 'Host' first field (the name) ... + for (i = 0; i < (int) strlen(Host); i++) { + if (Host[i] == '.') + break; + } + strncpy(fH, Host, i); + fH[i] = '\0'; + // ... and also the second one (the domain) + strcpy(sH, Host + i); + if (gDebug > 2) + ErrorInfo("RpdCheckHostWild: fH:%s sH:%s", fH, sH); + + // Now check the first field ... + j = 0; + k = fH; + for (i = 0; i < (int) strlen(host); i++) { + if (host[i] == '.') + break; + if (host[i] == '*') { + if (i > 0) { + // this is the part of name before the '*' .... + strncpy(dum, host + j, i - j); + dum[i - j] = '\0'; + if (gDebug > 2) + ErrorInfo("RpdCheckHostild: k:%s dum:%s", k, dum); + sp = strstr(k, dum); + if (sp == 0) { + rc = 1; + goto exit; + } + j = i + 1; + k = sp + strlen(dum) + 1; + } else + j++; + } + } + // Now check the domain name (if the name matches ...) + if (rc == 0) { + strcpy(dum, host + i); + if (gDebug > 2) + ErrorInfo("RpdCheckHostild: sH:%s dum:%s", sH, dum); + sp = strstr(sH, dum); + if (sp == 0) + rc = 1; + } + + exit: + // Release allocated memory ... + SafeDelete(fH); + SafeDelete(sH); + SafeDelete(dum); + + return rc; +} + +//______________________________________________________________________________ +char *RpdGetIP(const char *host) +{ + // Get IP address of 'host' as a string. String must be deleted by + // the user. + + struct hostent *h; + unsigned long ip; + unsigned char ip_fld[4]; + + // Check server name + if ((h = gethostbyname(host)) == 0) { + ErrorInfo("RpdGetIP: unknown host %s", host); + return 0; + } + // Decode ... + ip = ntohl(*(unsigned long *) h->h_addr_list[0]); + ip_fld[0] = (unsigned char) ((0xFF000000 & ip) >> 24); + ip_fld[1] = (unsigned char) ((0x00FF0000 & ip) >> 16); + ip_fld[2] = (unsigned char) ((0x0000FF00 & ip) >> 8); + ip_fld[3] = (unsigned char) ((0x000000FF & ip)); + + // Prepare output + char *output = new char[20]; + sprintf(output, "%d.%d.%d.%d", + ip_fld[0], ip_fld[1], ip_fld[2], ip_fld[3]); + + // return + return output; +} + +//______________________________________________________________________________ +void RpdSendAuthList() +{ + // Send list of authentication methods not yet tried. + + if (gDebug > 2) + ErrorInfo("RpdSendAuthList: analyzing (gNumLeft: %d)", gNumLeft); + + // Send Number of methids left + NetSend(gNumLeft, kROOTD_NEGOTIA); + + if (gNumLeft > 0) { + int i, ldum = gNumLeft * 3; + char *sdum = new char[ldum]; + sdum[0] = '\0'; + for (i = 0; i < gNumAllow; i++) { + if (gDebug > 2) + ErrorInfo("RpdSendAuthList: gTriedMeth[%d]: %d", i, + gTriedMeth[i]); + if (gTriedMeth[i] == 0) { + sprintf(sdum, "%s %d", sdum, gAllowMeth[i]); + } + } + NetSend(sdum, ldum, kMESS_STRING); + if (gDebug > 2) + ErrorInfo("RpdSendAuthList: sent list: %s", sdum); + SafeDelete(sdum); + } +} + + +//______________________________________________________________________________ +void RpdSshAuth(const char *sstr) +{ + // Reset global variable. + + gAuth = 0; + + if (gDebug > 2) + ErrorInfo("RpdSshAuth: contacted by host: %s for user %s", gOpenHost, + sstr); + + // Decode subject string + char *User = new char[strlen(sstr)], *Pipe = new char[strlen(sstr)]; + int Ulen, ofs, opt; + char dumm[20]; + sscanf(sstr, "%d %d %d %s %d %s %s", &gRemPid, &ofs, &opt, Pipe, &Ulen, + User, dumm); + User[Ulen] = '\0'; + gReUseRequired = (opt & kAUTH_REUSE_MSK); + + // Check if we have been called to notify failure ... + if (gRemPid < 0) { + if (gDebug > 2) + ErrorInfo + ("RpdSshAuth: this is a failure notification (%s,%s,%d,%s)", + User, gOpenHost, gRemPid, Pipe); + if (SshToolNotifyFailure(Pipe)) { + ErrorInfo + ("RpdSshAuth: failure notification perhaps unsuccessful ... "); + } + SafeDelete(User); + SafeDelete(Pipe); + return; + } + // Check user existence and get its environment + struct passwd *pw = getpwnam(User); + if (!pw) { + ErrorInfo("RpdSshAuth: entry for user % not found in /etc/passwd", + User); + NetSend(-2, kROOTD_SSH); + SafeDelete(User); + SafeDelete(Pipe); + return; + } + // Method cannot be attempted for anonymous users ... (ie data servers )... + if (!strcmp(pw->pw_shell, "/bin/false")) { + ErrorInfo("RpdSshAuth: no SSH for anonymous user '%s' ", User); + NetSend(-2, kROOTD_SSH); + SafeDelete(User); + SafeDelete(Pipe); + return; + } + + // Now we create an internal (UNIX) socket to listen to the result of sshd from ssh2rpd + // Path will be /tmp/rootdSSH_<random_string> + int UnixFd; + char *UniquePipe = new char[20]; + if ((UnixFd = + SshToolAllocateSocket(pw->pw_uid, pw->pw_gid, &UniquePipe)) < 0) { + ErrorInfo + ("RpdSshAuth: can't allocate UNIX socket for authentication"); + NetSend(0, kROOTD_SSH); + SafeDelete(User); + SafeDelete(Pipe); + SafeDelete(UniquePipe); + return; + } + // Communicate command to be executed via ssh ... + char *CmdInfo = new char[kMAXPATHLEN]; + if (gRootLog == 0 && strlen(gFileLog) > 0) { + sprintf(CmdInfo, "%s/ssh2rpd %d %s %d %d %s", gExecDir, gDebug, + UniquePipe, getpid(), gRemPid, gFileLog); + } else { + sprintf(CmdInfo, "%s/ssh2rpd %d %s %d %d", gExecDir, gDebug, + UniquePipe, getpid(), gRemPid); + } + if (gSshdPort != 22) { + sprintf(CmdInfo, "%s port:%d", CmdInfo, gSshdPort); + } + + if (gDebug > 2) + ErrorInfo("RpdSshAuth: sending CmdInfo (%d) %s", strlen(CmdInfo), + CmdInfo); + NetSend(strlen(CmdInfo), kROOTD_SSH); + NetSend(CmdInfo, strlen(CmdInfo), kROOTD_SSH); + + // Wait for verdict form sshd (via ssh2rpd ...) + gAuth = SshToolGetAuth(UnixFd); + + // Close socket + SshToolDiscardSocket(UniquePipe, UnixFd); + + // If failure, notify and return ... + if (gAuth == 0) { + NetSend(kErrAuthNotOK, kROOTD_ERR); // Send message length first + SafeDelete(User); + SafeDelete(Pipe); + SafeDelete(UniquePipe); + return; + } + // notify the client + if (gDebug > 0 && gAuth == 1) + ErrorInfo("RpdSshAuth: user %s authenticated by sshd", User); + + // Save username ... + strcpy(gUser, User); + + char line[kMAXPATHLEN]; + if ((gReUseAllow & kAUTH_SSH_MSK) && gReUseRequired) { + + // Ask for the RSA key + NetSend(1, kROOTD_RSAKEY); + + EMessageTypes kind; + NetRecv(gPubKey, kMAXPATHLEN, kind); + if (gDebug > 2) + ErrorInfo("RpdSshAuth: got RSA key: (%d) '%s' len: %d", kind, + gPubKey, strlen(gPubKey)); + + // Import Key and Determine key type + gRSAKey = RpdGetRSAKeys(gPubKey, 0); + if (gRSAKey == 0) { + ErrorInfo + ("RpdSshAuth: could not import a valid key - switch off reuse for this session"); + gReUseRequired = 0; + } + // Set an entry in the auth tab file for later (re)use, if required ... + int OffSet = -1; + char *token = 0; + if (gReUseRequired) { + sprintf(line, "%d %d %d %d %d %s %s", 4, 1, gRSAKey, getppid(), + gRemPid, gOpenHost, gUser); + OffSet = RpdUpdateAuthTab(1, line, &token); + } + // Comunicate login user name to client + sprintf(line, "%s %d", gUser, OffSet); + NetSend(strlen(line), kROOTD_SSH); // Send message length first + NetSend(line, kMESS_STRING); + + if (gReUseRequired) { + // Send over the token + if (RpdSecureSend(token) == -1) { + ErrorInfo + ("RpdSshAuth: problems secure-sending token - may result in corrupted token"); + } + SafeDelete(token); + + // Save RSA public key into file for later use by other rootd/proofd + RpdSavePubKey(gPubKey, OffSet); + } + } else { + // Comunicate login user name to client + sprintf(line, "%s -1", gUser); + NetSend(strlen(line), kROOTD_SSH); // Send message length first + NetSend(line, kMESS_STRING); + } + + // Release allocated memory + SafeDelete(User); + SafeDelete(Pipe); + SafeDelete(UniquePipe); + SafeDelete(CmdInfo); + + return; +} + +//______________________________________________________________________________ +void RpdKrb5Auth(const char *sstr) +{ + // Authenticate via Kerberos. + + gAuth = 0; + +#ifdef R__KRB5 + NetSend(1, kROOTD_KRB5); + // TAuthenticate will respond to our encouragement by sending krb5 + // authentication through the socket +#else + NetSend(0, kROOTD_KRB5); + return; +#endif + +#ifdef R__KRB5 + int retval; + + if (gDebug > 2) + ErrorInfo("RpdKrb5Auth: analyzing ... %s", sstr); + + if (gClientProtocol > 8) { + char *User = new char[strlen(sstr)]; + int Ulen, ofs, opt; + char dumm[20]; + // Decode subject string + sscanf(sstr, "%d %d %d %d %s %s", &gRemPid, &ofs, &opt, &Ulen, User, + dumm); + User[Ulen] = '\0'; + gReUseRequired = (opt & kAUTH_REUSE_MSK); + SafeDelete(User); + } + // get service principal + krb5_principal server; + if ((retval = krb5_sname_to_principal(gKcontext, 0, gService, + KRB5_NT_SRV_HST, &server))) { + ErrorInfo("RpdKrb5Auth: while generating service name (%s): %s", + gService, error_message(retval)); + return; + } + // listen for authentication from the client + krb5_auth_context auth_context = 0; + krb5_ticket *ticket; + char proto_version[100] = "krootd_v_1"; + int sock = gSockFd; + if ((retval = krb5_recvauth(gKcontext, &auth_context, + (krb5_pointer) &sock, proto_version, server, + 0, gKeytab, // default gKeytab is 0 + &ticket))) { + ErrorInfo("RpdKrb5Auth: recvauth failed--%s", error_message(retval)); + return; + } + // get client name + char *cname; + if ((retval = + krb5_unparse_name(gKcontext, ticket->enc_part2->client, &cname))) { + ErrorInfo("RpdKrb5Auth: unparse failed: %s", error_message(retval)); + return; + } + + using std::string; + string user = cname; + free(cname); + string reply = "authenticated as "; + reply += user; + + // set user name + user = user.erase(user.find("@")); // cut off realm + string::size_type pos = user.find("/"); // see if there is an instance + if (pos != string::npos) + user = user.erase(pos); // drop the instance + strncpy(gUser, user.c_str(), 64); + + NetSend(reply.c_str(), kMESS_STRING); + krb5_auth_con_free(gKcontext, auth_context); + + // Authentication was successfull + gAuth = 1; + + if (gClientProtocol > 8) { + + char line[kMAXPATHLEN]; + if ((gReUseAllow & kAUTH_KRB_MSK) && gReUseRequired) { + + // Ask for the RSA key + NetSend(1, kROOTD_RSAKEY); + + EMessageTypes kind; + NetRecv(gPubKey, kMAXPATHLEN, kind); + if (gDebug > 2) + ErrorInfo("RpdKrb5Auth: got RSA key: (%d) '%s' len: %d", kind, + gPubKey, strlen(gPubKey)); + + // Import key and determine its type + gRSAKey = RpdGetRSAKeys(gPubKey, 0); + if (gRSAKey == 0) { + ErrorInfo + ("RpdKrb5Auth: could not import a valid key - switch off reuse for this session"); + gReUseRequired = 0; + } + // Set an entry in the auth tab file for later (re)use, if required ... + int OffSet = -1; + char *token = 0; + if (gReUseRequired) { + sprintf(line, "%d %d %d %d %d %s %s", 2, 1, gRSAKey, getppid(), + gRemPid, gOpenHost, gUser); + OffSet = RpdUpdateAuthTab(1, line, &token); + if (gDebug > 2) + ErrorInfo("RpdKrb5Auth: line:%s OffSet:%d", line, OffSet); + } + // Comunicate login user name to client + sprintf(line, "%s %d", gUser, OffSet); + NetSend(strlen(line), kROOTD_KRB5); // Send message length first + NetSend(line, kMESS_STRING); + + // Send Token + if (gReUseRequired) { + if (RpdSecureSend(token) == -1) { + ErrorInfo + ("RpdKerb5Auth: problems secure-sending token - may result in corrupted token"); + } + SafeDelete(token); + + // Save RSA public key into file for later use by other rootd/proofd + RpdSavePubKey(gPubKey, OffSet); + } + + } else { + + // Comunicate login user name to client + sprintf(line, "%s -1", gUser); + NetSend(strlen(line), kROOTD_KRB5); // Send message length first + NetSend(line, kMESS_STRING); + + } + } else { + NetSend(user.c_str(), kMESS_STRING); + } + + if (gDebug > 0) + ErrorInfo("RpdKrb5Auth: user %s authenticated", gUser); + +#endif +} + +//______________________________________________________________________________ +void RpdSRPUser(const char *sstr) +{ + // Use Secure Remote Password protocol. + // Check user id in $HOME/.srootdpass file. + + gAuth = 0; + + if (!*sstr) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo("RpdSRPUser: bad user name"); + return; + } + + if (kSRootdPass[0]) { + } // remove compiler warning + +#ifdef R__SRP + + char srootdpass[kMAXPATHLEN], srootdconf[kMAXPATHLEN]; + + // Decode subject string + char *user = new char[strlen(sstr) + 1]; + if (gClientProtocol > 8) { + int Ulen, ofs, opt; + char dumm[20]; + sscanf(sstr, "%d %d %d %d %s %s", &gRemPid, &ofs, &opt, &Ulen, user, + dumm); + user[Ulen] = '\0'; + gReUseRequired = (opt & kAUTH_REUSE_MSK); + } else { + strcpy(user, sstr); + } + + struct passwd *pw = getpwnam(user); + if (!pw) { + NetSend(kErrNoUser, kROOTD_ERR); + ErrorInfo("RpdSRPUser: user %s unknown", user); + return; + } + // Method cannot be attempted for anonymous users ... (ie data servers )... + if (!strcmp(pw->pw_shell, "/bin/false")) { + NetSend(kErrNotAllowed, kROOTD_ERR); + ErrorInfo("RpdSRPUser: no SRP for anonymous user '%s' ", user); + return; + } + // If server is not started as root and user is not same as the + // one who started rootd then authetication is not ok. + uid_t uid = getuid(); + if (uid && uid != pw->pw_uid) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo("RpdSRPUser: user not same as effective user of rootd"); + return; + } + + NetSend(gAuth, kROOTD_AUTH); + + strcpy(gUser, user); + + SafeDelete(user); + + if (!gAltSRP) { + sprintf(srootdpass, "%s/%s", pw->pw_dir, kSRootdPass); + sprintf(srootdconf, "%s/%s.conf", pw->pw_dir, kSRootdPass); + } else { + sprintf(srootdpass, "%s", gAltSRPPass); + sprintf(srootdconf, "%s.conf", gAltSRPPass); + } + + FILE *fp1 = fopen(srootdpass, "r"); + if (!fp1) { + NetSend(kErrFileOpen, kROOTD_ERR); + ErrorInfo("RpdSRPUser: error opening %s", srootdpass); + return; + } + FILE *fp2 = fopen(srootdconf, "r"); + if (!fp2) { + NetSend(kErrFileOpen, kROOTD_ERR); + ErrorInfo("RpdSRPUser: error opening %s", srootdconf); + if (fp1) + fclose(fp1); + return; + } + + struct t_pw *tpw = t_openpw(fp1); + if (!tpw) { + NetSend(kErrFileOpen, kROOTD_ERR); + ErrorInfo("RpdSRPUser: unable to open password file %s", srootdpass); + fclose(fp1); + fclose(fp2); + return; + } + + struct t_conf *tcnf = t_openconf(fp2); + if (!tcnf) { + NetSend(kErrFileOpen, kROOTD_ERR); + ErrorInfo("RpdSRPUser: unable to open configuration file %s", + srootdconf); + t_closepw(tpw); + fclose(fp1); + fclose(fp2); + return; + } +#if R__SRP_1_1 + struct t_server *ts = t_serveropen(gUser, tpw, tcnf); +#else + struct t_server *ts = t_serveropenfromfiles(gUser, tpw, tcnf); +#endif + if (!ts) { + NetSend(kErrNoUser, kROOTD_ERR); + ErrorInfo("RpdSRPUser: user %s not found SRP password file", gUser); + return; + } + + if (tcnf) + t_closeconf(tcnf); + if (tpw) + t_closepw(tpw); + if (fp2) + fclose(fp2); + if (fp1) + fclose(fp1); + + char hexbuf[MAXHEXPARAMLEN]; + + // send n to client + NetSend(t_tob64(hexbuf, (char *) ts->n.data, ts->n.len), kROOTD_SRPN); + // send g to client + NetSend(t_tob64(hexbuf, (char *) ts->g.data, ts->g.len), kROOTD_SRPG); + // send salt to client + NetSend(t_tob64(hexbuf, (char *) ts->s.data, ts->s.len), + kROOTD_SRPSALT); + + struct t_num *B = t_servergenexp(ts); + + // receive A from client + EMessageTypes kind; + if (NetRecv(hexbuf, MAXHEXPARAMLEN, kind) < 0) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdSRPUser: error receiving A from client"); + return; + } + if (kind != kROOTD_SRPA) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdSRPUser: expected kROOTD_SRPA message"); + return; + } + + unsigned char buf[MAXPARAMLEN]; + struct t_num A; + A.data = buf; + A.len = t_fromb64((char *) A.data, hexbuf); + + // send B to client + NetSend(t_tob64(hexbuf, (char *) B->data, B->len), kROOTD_SRPB); + + t_servergetkey(ts, &A); + + // receive response from client + if (NetRecv(hexbuf, MAXHEXPARAMLEN, kind) < 0) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdSRPUser: error receiving response from client"); + return; + } + if (kind != kROOTD_SRPRESPONSE) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdSRPUser: expected kROOTD_SRPRESPONSE message"); + return; + } + + unsigned char cbuf[20]; + t_fromhex((char *) cbuf, hexbuf); + + if (!t_serververify(ts, cbuf)) { + + // authentication successful + if (gDebug > 0) + ErrorInfo("RpdSRPUser: user %s authenticated", gUser); + gAuth = 1; + + if (gClientProtocol > 8) { + + char line[kMAXPATHLEN]; + if ((gReUseAllow & kAUTH_SRP_MSK) && gReUseRequired) { + + // Ask for the RSA key + NetSend(1, kROOTD_RSAKEY); + + NetRecv(gPubKey, kMAXPATHLEN, kind); + if (gDebug > 2) + ErrorInfo("RpdSRPAuth: got RSA key: (%d) '%s' len: %d", + kind, gPubKey, strlen(gPubKey)); + + // Import key and determine its type + gRSAKey = RpdGetRSAKeys(gPubKey, 0); + if (gRSAKey == 0) { + ErrorInfo + ("RpdSRPAuth: could not import a valid key - switch off reuse for this session"); + gReUseRequired = 0; + } + + // Set an entry in the auth tab file for later (re)use, if required ... + int OffSet = -1; + char *token = 0; + if (gReUseRequired) { + sprintf(line, "%d %d %d %d %d %s %s", 1, 1, gRSAKey, + getppid(), gRemPid, gOpenHost, gUser); + OffSet = RpdUpdateAuthTab(1, line, &token); + } + // Comunicate login user name to client + sprintf(line, "%s %d", gUser, OffSet); + NetSend(strlen(line), kROOTD_SRPUSER); // Send message length first + NetSend(line, kMESS_STRING); + + if (gReUseRequired) { + // Send Token + if (RpdSecureSend(token) == -1) { + ErrorInfo + ("RpdKrb5Auth: problems secure-sending token - may result in corrupted token"); + } + SafeDelete(token); + + // Save RSA public key into file for later use by other rootd/proofd + RpdSavePubKey(gPubKey, OffSet); + } + + } else { + // Comunicate login user name to client + sprintf(line, "%s -1", gUser); + NetSend(strlen(line), kROOTD_SRPUSER); // Send message length first + NetSend(line, kMESS_STRING); + } + + } + + } else { + if (gClientProtocol > 8) { + NetSend(kErrBadPasswd, kROOTD_ERR); + ErrorInfo("RpdSRPUser: authentication failed for user %s", gUser); + return; + } + } + + t_serverclose(ts); + +#else + NetSend(0, kROOTD_SRPUSER); +#endif +} + +//______________________________________________________________________________ +int RpdCheckSpecialPass(const char *passwd) +{ + // Check user's password against password in $HOME/.rootdpass. If matches + // skip other authentication mechanism. Returns 1 in case of success + // authentication, 0 otherwise. + + char rootdpass[kMAXPATHLEN]; + + struct passwd *pw = getpwnam(gUser); + + sprintf(rootdpass, "%s/%s", pw->pw_dir, kRootdPass); + + int fid = open(rootdpass, O_RDONLY); + if (fid == -1) + return 0; + + int n; + if ((n = read(fid, rootdpass, sizeof(rootdpass) - 1)) <= 0) { + close(fid); + return 0; + } + close(fid); + + rootdpass[n] = 0; + char *s = strchr(rootdpass, '\n'); + if (s) + *s = 0; + + n = strlen(rootdpass); + + if (strncmp(passwd, rootdpass, n + 1) != 0) + return 0; + + if (gDebug > 0) + ErrorInfo + ("RpdCheckSpecialPass: user %s authenticated via ~/.rootdpass", + gUser); + + return 1; +} + +//______________________________________________________________________________ +void RpdPass(const char *pass) +{ + // Check user's password. + + char passwd[64]; + char *passw; + char *pass_crypt; + struct passwd *pw; +#ifdef R__SHADOWPW + struct spwd *spw; +#endif +#ifdef R__AFS + char *reason; + int afs_auth = 0; +#endif + + if (gDebug > 2) + ErrorInfo("RpdPass: Enter"); + + gAuth = 0; + if (!*gUser) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdPass: user needs to be specified first"); + return; + } + + int n = strlen(pass); + // Passwd length should be in the correct range ... + if (!n) { + NetSend(kErrBadPasswd, kROOTD_ERR); + ErrorInfo("RpdPass: null passwd not allowed"); + return; + } + if (n > (int) sizeof(passwd)) { + NetSend(kErrBadPasswd, kROOTD_ERR); + ErrorInfo("RpdPass: passwd too long"); + return; + } + // Inversion is done in RpdUser, if needed + strcpy(passwd, pass); + + // Special treatment for anonimous ... + if (gAnon) { + strcpy(gPasswd, passwd); + goto authok; + } + // ... and SpecialPass ... + if (RpdCheckSpecialPass(passwd)) { + goto authok; + } + // Get local passwd info for gUser + pw = getpwnam(gUser); + +#ifdef R__AFS + afs_auth = !ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, + gUser, //user name + (char *) 0, //instance + (char *) 0, //realm + passwd, //password + 0, //default lifetime + 0, 0, //two spares + &reason); //error string + + if (!afs_auth) { + ErrorInfo("RpdPass: AFS login failed for user %s: %s", gUser, + reason); + // try conventional login... +#endif + +#ifdef R__SHADOWPW + // System V Rel 4 style shadow passwords + if ((spw = getspnam(gUser)) == 0) { + ErrorInfo("RpdPass: Shadow passwd not available for user %s", + gUser); + passw = pw->pw_passwd; + } else + passw = spw->sp_pwdp; +#else + passw = pw->pw_passwd; +#endif + // if (gClientProtocol <= 8 || !gReUseRequired) { + if (gClientProtocol <= 8 || !gCryptRequired) { + pass_crypt = crypt(passwd, passw); // Comment this + } else { + pass_crypt = passwd; + } + n = strlen(passw); + + if (strncmp(pass_crypt, passw, n + 1) != 0) { + NetSend(kErrBadPasswd, kROOTD_ERR); + ErrorInfo("RpdPass: invalid password for user %s", gUser); + return; + } +#ifdef R__AFS + } // afs_auth +#endif + + authok: + gAuth = 1; + + if (gClientProtocol > 8) { + // Set an entry in the auth tab file for later (re)use, if required ... + int OffSet = -1; + char *token = 0; + char line[kMAXPATHLEN]; + if ((gReUseAllow & kAUTH_CLR_MSK) && gReUseRequired) { + + sprintf(line, "%d %d %d %d %d %s %s", 0, 1, gRSAKey, getppid(), + gRemPid, gOpenHost, gUser); + OffSet = RpdUpdateAuthTab(1, line, &token); + if (gDebug > 2) + ErrorInfo("RpdPass: got offset %d", OffSet); + + // Comunicate login user name to client + sprintf(line, "%s %d", gUser, OffSet); + if (gDebug > 2) + ErrorInfo("RpdPass: sending back line %s", line); + NetSend(strlen(line), kROOTD_PASS); // Send message length first + NetSend(line, kMESS_STRING); + + if (gDebug > 2) + ErrorInfo("RpdPass: sending token %s (Crypt: %d)", token, + gCryptRequired); + if (gCryptRequired) { + // Send over the token + if (RpdSecureSend(token) == -1) { + ErrorInfo + ("RpdPass: problems secure-sending token - may result in corrupted token"); + } + } else { + // Send token inverted + for (int i = 0; i < (int) strlen(token); i++) { + token[i] = ~token[i]; + } + NetSend(token, kMESS_STRING); + } + SafeDelete(token); + + } else { + // Comunicate login user name to client + sprintf(line, "%s -1", gUser); + if (gDebug > 2) + ErrorInfo("RpdPass: sending back line %s", line); + NetSend(strlen(line), kROOTD_PASS); // Send message length first + NetSend(line, kMESS_STRING); + } + + if (gCryptRequired) { + // Save RSA public key into file for later use by other rootd/proofd + RpdSavePubKey(gPubKey, OffSet); + } + } +} + +//______________________________________________________________________________ +void RpdGlobusAuth(const char *sstr) +{ + // Authenticate via Globus. + + gAuth = 0; + +#ifndef R__GLBS + + if (sstr) { } // use sstr + NetSend(0, kROOTD_GLOBUS); + return; + +#else + + OM_uint32 MajStat = 0; + OM_uint32 MinStat = 0; + OM_uint32 GssRetFlags = 0; + gss_ctx_id_t GlbContextHandle = GSS_C_NO_CONTEXT; + gss_cred_id_t GlbCredHandle = GSS_C_NO_CREDENTIAL; + gss_cred_id_t GlbDelCredHandle = GSS_C_NO_CREDENTIAL; + int GlbTokenStatus = 0; + char *GlbClientName; + FILE *FILE_SockFd; + char *gridmap_default = "/etc/grid-security/grid-mapfile"; + EMessageTypes kind; + int lSubj, OffSet = -1; + char *user = 0; + int ulen = 0; + + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: contacted by host: %s", gOpenHost); + + // Tell the remote client that we may accept Globus credentials ... + NetSend(1, kROOTD_GLOBUS); + + // Decode subject string + char *Subj = new char[strlen(sstr) + 1]; + int opt; + char dumm[20]; + sscanf(sstr, "%d %d %d %d %s %s", &gRemPid, &OffSet, &opt, &lSubj, Subj, + dumm); + Subj[lSubj] = '\0'; + gReUseRequired = (opt & kAUTH_REUSE_MSK); + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: gRemPid: %d, Subj: %s (%d %d)", gRemPid, + Subj, lSubj, strlen(Subj)); + SafeDelete(Subj); // GlbClientName will be determined from the security context ... + + // Now wait for client to communicate the issuer name of the certificate ... + char *answer = new char[20]; + NetRecv(answer, (int) sizeof(answer), kind); + if (kind != kMESS_STRING) { + Error(gErr, kErrAuthNotOK, + "RpdGlobusAuth: client_issuer_name:received unexpected type of message (%d)", + kind); + return; + } + int client_issuer_name_len = atoi(answer); + SafeDelete(answer); + char *client_issuer_name = new char[client_issuer_name_len + 1]; + NetRecv(client_issuer_name, client_issuer_name_len, kind); + if (kind != kMESS_STRING) { + Error(gErr, kErrAuthNotOK, + "RpdGlobusAuth: client_issuer_name:received unexpected type of message (%d)", + kind); + return; + } + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: client issuer name is: %s", + client_issuer_name); + + // Now we open the certificates and we check if we are able to autheticate the client + // In the affirmative case we sen our subject name to the client ... + char *subject_name; + if (GlbsToolCheckCert(client_issuer_name, &subject_name)) { + ErrorInfo + ("RpdGlobusAuth: host does not seem to have certificate for the requested CA (%s)", + client_issuer_name); + NetSend(0, kROOTD_GLOBUS); // Notify that we did not find it + return; + } else { + int sjlen = strlen(subject_name) + 1; + subject_name[sjlen] = '\0'; + + int bsnd = NetSend(sjlen, kROOTD_GLOBUS); + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: sent: %d (due >=%d))", bsnd, + 2 * sizeof(sjlen)); + + bsnd = NetSend(subject_name, sjlen, kMESS_STRING); + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: sent: %d (due >=%d))", bsnd, sjlen); + + free(subject_name); + } + // not needed anymore ... + SafeDelete(client_issuer_name); + + // Inquire Globus credentials: + // This is looking to file X509_USER_CERT for valid a X509 cert (default + // /etc/grid-security/hostcert.pem) and to dir X509_CERT_DIR for trusted CAs + // (default /etc/grid-security/certificates). + if ((MajStat = + globus_gss_assist_acquire_cred(&MinStat, GSS_C_ACCEPT, + &GlbCredHandle)) != + GSS_S_COMPLETE) { + GlbsToolError("RpdGlobusAuth: gss_assist_acquire_cred", MajStat, + MinStat, 0); + if (getuid() > 0) { + ErrorInfo + ("RpdGlobusAuth: non-root: make sure you have initialized (manually) your proxies"); + } + return; + } + // We need to associate a FILE* stream with the socket + // It will automatically closed when the socket will be closed ... + FILE_SockFd = fdopen(gSockFd, "w+"); + + // Now we are ready to start negotiating with the Client + if ((MajStat = + globus_gss_assist_accept_sec_context(&MinStat, &GlbContextHandle, + GlbCredHandle, &GlbClientName, + &GssRetFlags, 0, + &GlbTokenStatus, + &GlbDelCredHandle, + globus_gss_assist_token_get_fd, + (void *) FILE_SockFd, + globus_gss_assist_token_send_fd, + (void *) FILE_SockFd)) != + GSS_S_COMPLETE) { + GlbsToolError("RpdGlobusAuth: gss_assist_accept_sec_context", + MajStat, MinStat, GlbTokenStatus); + return; + } else { + gAuth = 1; + if (gDebug > 0) + ErrorInfo("RpdGlobusAuth: user: %s \n authenticated", + GlbClientName); + } + + // If we are master we need to autheticate the slaves ... + if (gGlobus == 1) { // There might be the need of credentials ... + // Check that we got delegation to autheticate the slaves + if (GssRetFlags | GSS_C_DELEG_FLAG) { + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: Pointer to del cred is 0x%x", + (int) GlbDelCredHandle); + } else { + Error(gErr, kErrAuthNotOK, + "RpdGlobusAuth: did not get delegated credentials (RetFlags: 0x%x)", + GssRetFlags); + return; + } + // Now we have to export these delegated credentials to a shared memory segment + // for later use in 'proofserv' ... + // credential= (gss_buffer_t)malloc(sizeof(gss_buffer_desc)); + gss_buffer_t credential = new gss_buffer_desc; + if ((MajStat = + gss_export_cred(&MinStat, GlbDelCredHandle, 0, 0, + credential)) != GSS_S_COMPLETE) { + GlbsToolError("RpdGlobusAuth: gss_export_cred", MajStat, MinStat, + 0); + return; + } else if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: credentials prepared for export"); + + // Now store it in shm for later use in proofserv ... + int rc; + if ((rc = GlbsToolStoreToShm(credential, &gShmIdCred))) { + ErrorInfo + ("RpdGlobusAuth: credentials not correctly stored in shm (rc: %d)", + rc); + } + if (gDebug > 2) + ErrorInfo + ("RpdGlobusAuth: credentials stored in shared memory segment %d", + gShmIdCred); + + delete credential; + } + // For Now we set the gUser to the certificate owner using the gridmap file ... + // Should be understood if this is really necessary ... + if (getenv("GRIDMAP") == 0) { + // The installation did not specify a special location for the gridmap file + // We assume the usual default ... + setenv("GRIDMAP", gridmap_default, 1); + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: gridmap: using default file (%s)", + gridmap_default); + } else if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: gridmap: using file %s", + getenv("GRIDMAP")); + + // Get local login name for the subject ... + if (globus_gss_assist_gridmap(GlbClientName, &user)) { + if (gDebug > 2) + ErrorInfo + ("RpdGlobusAuth: unable to get local username from gridmap: using: %s", + gAnonUser); + user = strdup(gAnonUser); + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: user ", user); + } + if (!strcmp(user, "anonymous")) + user = strdup(gAnonUser); + if (!strcmp(user, gAnonUser)) + gAnon = 1; + + // Fill gUser and free allocated memory + ulen = strlen(user); + strncpy(gUser, user, ulen + 1); + + char line[kMAXPATHLEN]; + if ((gReUseAllow & kAUTH_GLB_MSK) && gReUseRequired) { + + // Ask for the RSA key + NetSend(1, kROOTD_RSAKEY); + + NetRecv(gPubKey, kMAXPATHLEN, kind); + if (gDebug > 2) + ErrorInfo("RpdGlobusAuth: got RSA key: (%d) '%s' len: %d", kind, + gPubKey, strlen(gPubKey)); + + // Import key and determine its type + gRSAKey = RpdGetRSAKeys(gPubKey, 0); + if (gRSAKey == 0) { + ErrorInfo + ("RpdGlobusAuth: could not import a valid key - switch off reuse for this session"); + gReUseRequired = 0; + } + // Store security context and related info for later use ... + OffSet = -1; + char *token = 0; + if (gReUseRequired) { + int ShmId = GlbsToolStoreContext(GlbContextHandle, user); + if (ShmId > 0) { + sprintf(line, "%d %d %d %d %d %s %s %d %s", 3, 1, gRSAKey, + getppid(), gRemPid, gOpenHost, user, ShmId, + GlbClientName); + OffSet = RpdUpdateAuthTab(1, line, &token); + } else if (gDebug > 0) + ErrorInfo + ("RpdGlobusAuth: unable to export context to shm for later use"); + } + // Comunicate login user name to client (and token) + sprintf(line, "%s %d", gUser, OffSet); + NetSend(strlen(line), kROOTD_GLOBUS); // Send message length first + NetSend(line, kMESS_STRING); + + if (gReUseRequired) { + // Send Token + if (RpdSecureSend(token) == -1) { + ErrorInfo + ("RpdGlobusAuth: problems secure-sending token - may result in corrupted token"); + } + SafeDelete(token); + + // Save RSA public key into file for later use by other rootd/proofd + RpdSavePubKey(gPubKey, OffSet); + } + } else { + // Comunicate login user name to client (and token) + sprintf(line, "%s %d", gUser, OffSet); + NetSend(strlen(line), kROOTD_GLOBUS); // Send message length first + NetSend(line, kMESS_STRING); + } + + // and free allocated memory + free(user); + free(GlbClientName); + + if (gDebug > 0) + ErrorInfo("RpdGlobusAuth: logging as %s ", gUser); + +#endif +} + +//______________________________________________________________________________ +void RpdRfioAuth(const char *sstr) +{ + // Check if user and group id specified in the request exist in the + // passwd file. If they do then grant access. Very insecure: to be used + // with care. + + gAuth = 0; + + if (gDebug > 2) + ErrorInfo("RpdRfioAuth: analyzing ... %s", sstr); + + if (!*sstr) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo("RpdRfioAuth: subject string is empty"); + return; + } + // Decode subject string + unsigned int uid, gid; + sscanf(sstr, "%d %d", &uid, &gid); + + // Now inquire passwd ... + struct passwd *pw; + if ((pw = getpwuid((uid_t) uid)) == 0) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo("RpdRfioAuth: uid %d not found", uid); + return; + } + // Check if authorized + char cuid[20]; + sprintf(cuid, "%d", uid); + if (gUserIgnLen[5] > 0 && strstr(gUserIgnore[5], cuid) != 0) { + NetSend(kErrNotAllowed, kROOTD_ERR); + ErrorInfo + ("RpdRfioAuth: user (%d,%s) not authorized to use (uid:gid) method", + uid, pw->pw_name); + return; + } + if (gUserAlwLen[5] > 0 && strstr(gUserAllow[5], cuid) == 0) { + NetSend(kErrNotAllowed, kROOTD_ERR); + ErrorInfo + ("RpdRfioAuth: user (%d,%s) not authorized to use (uid:gid) method", + uid, pw->pw_name); + return; + } + + // Now check group id ... + if (gid != pw->pw_gid) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo + ("RpdRfioAuth: group id does not match (remote:%d,local:%d)", + gid, pw->pw_gid); + return; + } + // Set username .... + strcpy(gUser, pw->pw_name); + + + // Notify, if required ... + if (gDebug > 0) + ErrorInfo("RpdRfioAuth: user %s authenticated (uid:%d, gid:%d)", + gUser, uid, gid); + + // Set Auth flag + gAuth = 1; +} + +//______________________________________________________________________________ +void RpdCleanup(const char *sstr) +{ + // Cleanup auth table. + + char Host[kMAXPATHLEN] = { 0 }; + int rPid; + + sscanf(sstr, "%d %s", &rPid, Host); + if (gDebug > 2) + ErrorInfo("RpdCleanup: contacted by remote Host: %s, Pid: %d", Host, + rPid); + + // Cleanup Auth tab + int ns; + if ((ns = RpdCleanupAuthTab(Host, rPid))) + ErrorInfo("RpdCleanup: %d not properly cleaned", ns); + + // Trim Auth Tab file if call via RootdTerm (typically when rootd is shutting down ... ) + if (!strcmp(Host, "all") || (rPid == 0)) + RpdUpdateAuthTab(0, 0, 0); +} + +//______________________________________________________________________________ +void RpdCheckSession(int period) +{ + // Period in seconds. + + int speriod = 3600 * period; + + if (gDebug > 2) + ErrorInfo("RpdCheckSession: enter: period: %d", period); + + // Session file ... + char SessionFile[kMAXPATHLEN] = { 0 }; + // sprintf(SessionFile, "%s/rootd.%d", gTmpDir, getppid()); + sprintf(SessionFile, "%s/rpd.run", gTmpDir); + + // Reset + int i; + gNumAllow = gNumLeft = 0; + for (i = 0; i < kMAXSEC; i++) { + gAllowMeth[i] = -1; + gHaveMeth[i] = 1; + } + + if (gDebug > 2) + ErrorInfo("RpdCheckSession: sessionfile: %s", SessionFile); + + // If it already exists, update auth tab or do nothing ... + struct stat st; + if (stat(SessionFile, &st) == 0) { + if (gDebug > 2) + ErrorInfo("RpdCheckSession: stat ok: mtime: %d", st.st_mtime); + if ((time(0) - st.st_mtime) > speriod) + RpdUpdateAuthTab(0, 0, 0); + + FILE *fp = fopen(SessionFile, "r"); + + int ctim, nw; + char line[1024]; + int meth[5]; + while (fgets(line, sizeof(line), fp)) { + nw = sscanf(line, "%d %d %d %d %d %d", &ctim, &meth[4], &meth[0], + &meth[1], &meth[2], &meth[3]); + if (nw > 1) { + gNumAllow = meth[4]; + if (gNumAllow != (nw - 2)) { + ErrorInfo + ("RpdCheckSession: inconsistency found in session file ( gNumAllow:%d nw:%d) - rescan", + gNumAllow, nw); + goto rescan; + } else { + for (i = 0; i < gNumAllow; i++) { + if (meth[i] >= 0 && meth[i] <= kMAXSEC) { + gAllowMeth[i] = meth[i]; + gHaveMeth[meth[i]] = 1; + } else { + ErrorInfo + ("RpdCheckSession: inconsistency found in session file (meth[%d]: %d) - rescan", + i, meth[i]); + goto rescan; + } + } + gNumLeft = gNumAllow; + } + } + } + fclose(fp); + return; + rescan: + fclose(fp); + + } else { + if (errno != ENOENT) + ErrorInfo + ("RpdCheckSession: file exists but problems from stat: errno:%d - recreating the file", + errno); + } + + // Remove old files first ... + char cmd[kMAXPATHLEN] = { 0 }; + sprintf(cmd, "ls -1 %s/rootd.* 2>/dev/null", gTmpDir); + FILE *fp = popen(cmd, "r"); + i = 0; + if (fp != 0) { + int ch; + for (ch = fgetc(fp); ch != EOF; ch = fgetc(fp)) { + if (ch != 10) { + cmd[i++] = ch; + } else { + cmd[i] = '\0'; + unlink(cmd); + i = 0; + } + } + if (i > 0) { + cmd[i] = '\0'; + unlink(cmd); + } + pclose(fp); + } + // List of default authentication methods (to be save in the session file) + RpdDefaultAuthAllow(); + + char cmeth[200]; + cmeth[0] = '\0'; + sprintf(cmeth, "%d", gNumAllow); + for (i = 0; i < gNumAllow; i++) { + sprintf(cmeth, "%s %d", cmeth, gAllowMeth[i]); + } + + // Create new file ... + fp = fopen(SessionFile, "w"); + fprintf(fp, "%d %s\n", (int) time(0), cmeth); + fclose(fp); + + // CleauUp Authentication Table + RpdUpdateAuthTab(-1, 0, 0); +} + +//______________________________________________________________________________ +void RpdDefaultAuthAllow() +{ + // Check configuration options and running daemons to build a default list + // of secure methods. + + if (gDebug > 2) + ErrorInfo("RpdDefaultAuthAllow: Enter"); + + // UsrPwdClear + gAllowMeth[gNumAllow] = 0; + gNumAllow++; + gNumLeft++; + + // SSH + if (RpdCheckDaemon("sshd") > 0) { + if (RpdCheckSshd() > 0) { + gAllowMeth[gNumAllow] = 4; + gNumAllow++; + gNumLeft++; + } + } else if (RpdCheckSshd() > 0) { + if (gDebug > 0) + ErrorInfo + ("RpdDefaultAuthAllow: sshd not found by 'ps' but a process is listening on the specified port (%d)", + gSshdPort); + // Try at least connection to port ... + gAllowMeth[gNumAllow] = 4; + gNumAllow++; + gNumLeft++; + } + if (gNumAllow == 0) { + // Don't have this method + gHaveMeth[4] = 0; + } + // SRP +#ifdef R__SRP + gAllowMeth[gNumAllow] = 1; + gNumAllow++; + gNumLeft++; +#else + // Don't have this method + gHaveMeth[1] = 0; +#endif + + // Kerberos +#ifdef R__KRB5 + if (getuid() == 0) { + gAllowMeth[gNumAllow] = 2; + gNumAllow++; + gNumLeft++; + } else + gHaveMeth[2] = 0; +#else + // Don't have this method + gHaveMeth[2] = 0; +#endif + + // Globus +#ifdef R__GLBS + gAllowMeth[gNumAllow] = 3; + gNumAllow++; + gNumLeft++; +#else + // Don't have this method + gHaveMeth[3] = 0; +#endif + + if (gDebug > 2) { + int i; + char temp[200]; + temp[0] = '\0'; + if (gNumAllow == 0) + strcpy(temp, "none"); + for (i = 0; i < gNumAllow; i++) { + sprintf(temp, "%s %d", temp, gAllowMeth[i]); + } + ErrorInfo + ("RpdDefaultAuthAllow: default list of secure methods available: %s", + temp); + } +} + +//______________________________________________________________________________ +int RpdCheckDaemon(const char *daemon) +{ + // Check the running of process 'daemon'. + // Info got from 'ps ax'. + + char cmd[1024] = { 0 }; + int ch, i = 0, cnt = 0; + + if (gDebug > 2) + ErrorInfo("RpdCheckDaemon: Enter ... %s", daemon); + + // Return if empty + if (daemon == 0 || strlen(daemon) == 0) + return cnt; + + // Build command + sprintf(cmd, "ps ax | grep %s 2>/dev/null", daemon); + + // Run it ... + FILE *fp = popen(cmd, "r"); + if (fp != 0) { + for (ch = fgetc(fp); ch != EOF; ch = fgetc(fp)) { + if (ch != 10) { + cmd[i++] = ch; + } else { + cmd[i] = '\0'; + if (strstr(cmd, "grep") == 0 && strstr(cmd, "rootd") == 0 + && strstr(cmd, "proofd") == 0) { + cnt++; + if (gDebug > 2) + ErrorInfo("RpdCheckDaemon: read: %s", cmd); + } + i = 0; + } + } + if (i > 0) { + cmd[i] = '\0'; + cnt++; + if (gDebug > 2) + ErrorInfo("RpdCheckDaemon: read: %s", cmd); + } + pclose(fp); + if (gDebug > 2) + ErrorInfo("RpdCheckDaemon: read %d lines", cnt); + + } else { + ErrorInfo("RpdCheckDaemon: problems executing cmd ..."); + } + return cnt; +} + +//______________________________________________________________________________ +int RpdCheckSshd() +{ + // Tries to connect to sshd daemon on its standard port (22) + // Used if RpdCheckDaemon returns a negative result + + if (gDebug > 2) + ErrorInfo("RpdCheckSshd: Enter ... "); + + // Standard SSH port + // int SshdPort = 22; + + // First get local host address + struct hostent *h = gethostbyname("localhost"); + if (h == 0) { + // Make further attempt with HOSTNAME + if (getenv("HOSTNAME") == 0) { + ErrorInfo("RpdCheckSshd: unable to resolve local host name"); + return 0; + } else { + h = gethostbyname(getenv("HOSTNAME")); + if (h == 0) { + ErrorInfo + ("RpdCheckSshd: local host name is unknown to gethostbyname: '%s'", + getenv("HOSTNAME")); + return 0; + } + } + } + // Fill relevant sockaddr_in structure + struct sockaddr_in servAddr; + servAddr.sin_family = h->h_addrtype; + memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], + h->h_length); + servAddr.sin_port = htons(gSshdPort); + + // create AF_INET socket + int sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd < 0) { + ErrorInfo("RpdCheckSshd: cannot open new AF_INET socket (errno:%d) ", + errno); + return 0; + } + + /* bind any port number */ + struct sockaddr_in localAddr; + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = htonl(INADDR_ANY); + localAddr.sin_port = htons(0); + int rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr)); + if (rc < 0) { + ErrorInfo("RpdCheckSshd: cannot bind to local port %u", gSshdPort); + return 0; + } + // connect to server + rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr)); + if (rc < 0) { + ErrorInfo("RpdCheckSshd: cannot connect to local port %u", + gSshdPort); + return 0; + } + // Sshd successfully contacted + if (gDebug > 2) + ErrorInfo("RpdCheckSshd: success!"); + return 1; +} + +//______________________________________________________________________________ +void RpdUser(const char *sstr) +{ + // Check user id. If user id is not equal to rootd's effective uid, user + // will not be allowed access, unless effective uid = 0 (i.e. root). + const int kMaxBuf = 256; + char recvbuf[kMaxBuf]; + char rootdpass[kMAXPATHLEN]; + char specpass[64]; + EMessageTypes kind; + struct passwd *pw; +#ifdef R__SHADOWPW + struct spwd *spw; +#endif + if (gDebug > 2) + ErrorInfo("RpdUser: Enter ... %s", sstr); + + gAuth = 0; + + // Nothing can be done if empty message + if (!*sstr) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo("RpdUser: received empty string"); + return; + } + // Parse input message + char *user = new char[strlen(sstr) + 1]; + if (gClientProtocol > 8) { + int ulen, ofs, opt; + // Decode subject string + sscanf(sstr, "%d %d %d %d %s", &gRemPid, &ofs, &opt, &ulen, user); + user[ulen] = '\0'; + gReUseRequired = (opt & kAUTH_REUSE_MSK); + gCryptRequired = (opt & kAUTH_CRYPT_MSK); + gOffSet = ofs; + } else { + strcpy(user, sstr); + } + if (gDebug > 2) + ErrorInfo("RpdUser: gReUseRequired: %d gCryptRequired: %d", + gReUseRequired, gCryptRequired); + + ERootdErrors err = kErrNoUser; + if (!strcmp(gService, "rootd")) { + // Default anonymous account ... + if (!strcmp(user, "anonymous")) { + user[0] = '\0'; + strcpy(user, "rootd"); + } + } + + if ((pw = getpwnam(user)) == 0) { + NetSend(err, kROOTD_ERR); + ErrorInfo("RpdUser: user %s unknown", user); + return; + } + // Check if of type anonymous ... + if (!strcmp(pw->pw_shell, "/bin/false")) { + err = kErrNoAnon; + gAnon = 1; + gReUseRequired = 0; + } + // If server is not started as root and user is not same as the + // one who started rootd then authetication is not ok. + uid_t uid = getuid(); + if (uid && uid != pw->pw_uid) { + NetSend(kErrBadUser, kROOTD_ERR); + ErrorInfo("RpdUser: user not same as effective user of rootd"); + return; + } + // Check if authorized + // If not anonymous, try to get passwd + // (if our system uses shadow passwds and we are not superuser + // we cannot authenticate users ...) + char *passw = 0; + if (gAnon == 0) { +#ifdef R__SHADOWPW + // System V Rel 4 style shadow passwords + if ((spw = getspnam(user)) == 0) { + if (gDebug > 0) { + ErrorInfo("RpdUser: Shadow passwd not accessible for user %s",user); + ErrorInfo("RpdUser: trying normal or special root passwd"); + } + passw = pw->pw_passwd; + } else + passw = spw->sp_pwdp; +#else + passw = pw->pw_passwd; +#endif + if (strlen(passw) == 0 || !strcmp(passw, "x")) { + // Try if special password is given via .rootdpass + sprintf(rootdpass, "%s/%s", pw->pw_dir, kRootdPass); + + int fid = open(rootdpass, O_RDONLY); + if (fid != -1) { + int n; + if ((n = read(fid, specpass, sizeof(specpass) - 1)) > 0) { + passw = specpass; + } + close(fid); + } + } + // Check if successful + if (strlen(passw) == 0 || !strcmp(passw, "x")) { + NetSend(kErrNotAllowed, kROOTD_ERR); + ErrorInfo("RpdUser: passwd hash not available for user %s", user); + ErrorInfo + ("RpdUser: user %s cannot be authenticated with this method", + user); + return; + } + } + // Check if the administrator allows authentication + char cuid[20]; + sprintf(cuid, "%d", pw->pw_uid); + if (gUserIgnLen[0] > 0 && strstr(gUserIgnore[0], cuid) != 0) { + NetSend(kErrNotAllowed, kROOTD_ERR); + ErrorInfo + ("RpdUser: user (%d,%s) not authorized to use UsrPwd method", + uid, pw->pw_name); + return; + } + if (gUserAlwLen[0] > 0 && strstr(gUserAllow[0], cuid) == 0) { + NetSend(kErrNotAllowed, kROOTD_ERR); + ErrorInfo + ("RpdUser: user (%d,%s) not authorized to use UsrPwd method", + uid, pw->pw_name); + return; + } + // Ok: Save username and go to next steps + strcpy(gUser, user); + SafeDelete(user); + + if (gClientProtocol > 8) { + + // Prepare status flag to send back + if (gAnon == 1) { + // Anonymous user: we will receive a text pass in the form user@remote.host.dom + NetSend(-1, kROOTD_AUTH); + + } else { + + if (gCryptRequired) { + // Named user: first we receive a session public key + // Ask for the RSA key + NetSend(1, kROOTD_RSAKEY); + + NetRecv(gPubKey, kMAXPATHLEN, kind); + if (gDebug > 2) + ErrorInfo("RpdUser: got RSA key: (%d) '%s' len: %d", kind, + gPubKey, strlen(gPubKey)); + + // Import key and determine its type + gRSAKey = RpdGetRSAKeys(gPubKey, 0); + if (gRSAKey == 0) { + ErrorInfo + ("RpdUser: could not import a valid key - switch off reuse for this session"); + gReUseRequired = 0; + } + // Determine Salt + char Salt[20] = { 0 }; + int Slen = 0; + + if (gReUseRequired) { + if (!strncmp(passw, "$1$", 3)) { + // Shadow passwd + char *pd = strstr(passw + 4, "$"); + Slen = (int) (pd - passw); + strncpy(Salt, passw, Slen); + Salt[Slen] = 0; + } else { + Slen = 2; + strncpy(Salt, passw, Slen); + Salt[Slen] = 0; + } + if (gDebug > 2) + ErrorInfo("RpdUser: salt: '%s' ",Salt); + + // Send it over encrypted + if (RpdSecureSend(Salt) == -1) { + ErrorInfo + ("RpdUser: problems secure-sending salt - may result in corrupted salt"); + } + } else { + NetSend("-1", kMESS_STRING); + } + } else { + // We continue the aythentication process in clear + NetSend(0, kROOTD_AUTH); + } + } + + } else { + // If we are talking to a old client protocol + NetSend(0, kROOTD_AUTH); + } + + // Get the password hash or anonymous string + if (NetRecv(recvbuf, kMaxBuf, kind) < 0) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdUser: error receiving message"); + return; + } + if (kind != kROOTD_PASS) { + NetSend(kErrFatal, kROOTD_ERR); + ErrorInfo("RpdUser: received wrong message type: %d (expecting: %d)", + kind, (int) kROOTD_PASS); + return; + } + // Get passwd + char *passwd = 0; + if (gAnon == 0 && gClientProtocol > 8 && gCryptRequired) { + + // Receive encrypted pass hash + if (RpdSecureRecv(&passwd) == -1) { + ErrorInfo + ("RpdUser: problems secure-receiving pass hash - may result in authentication failure "); + } + + } else { + + // Receive clear or anonymous pass + passwd = new char[strlen(recvbuf) + 1]; + + // Re-invert pass + int i, n = strlen(recvbuf); + for (i = 0; i < n; i++) + passwd[i] = ~recvbuf[i]; + passwd[i] = '\0'; + + if (gDebug > 2 && gAnon) + ErrorInfo("RpdUser: received anonymous pass: '%s'", passwd); + } + + // Check the passwd and login if ok ... + RpdPass(passwd); + + SafeDelete(passwd); + +} + +//______________________________________________________________________________ +int RpdGuessClientProt(const char *buf, EMessageTypes kind) +{ + // Try a guess of the client protocol from what she/he sent over + // the net ... + + if (gDebug > 2) + ErrorInfo("RpdGuessClientProt: Enter: buf: '%s', kind: %d", buf, + (int) kind); + + // Assume same version as us. + int proto = 9; + + // Clear authentication + if (kind == kROOTD_USER) { + char usr[64], rest[256]; + int ns = sscanf(buf, "%s %s", usr, rest); + if (ns == 1) + proto = 8; + } + // SRP authentication + if (kind == kROOTD_SRPUSER) { + char usr[64], rest[256]; + int ns = sscanf(buf, "%s %s", usr, rest); + if (ns == 1) + proto = 8; + } + // Kerberos authentication + if (kind == kROOTD_KRB5) { + if (strlen(buf) == 0) + proto = 8; + } + + if (gDebug > 2) + ErrorInfo("RpdGuessClientProt: guess for gClientProtocol is %d", + proto); + + // Return the guess + return proto; +} + +//______________________________________________________________________________ +char *RpdGetRandString(int Opt, int Len) +{ + // Allocates and Fills a NULL terminated buffer of length Len+1 with + // Len random characters. + // Return pointer to the buffer (to be deleted by the caller) + // Opt = 0 any non dangerous char + // 1 letters and numbers (upper and lower case) + // 2 hex characters (upper and lower case) + // 3 crypt like [a-zA-Z0-9./] + + int iimx[4][4] = { { 0x0, 0xffffff08, 0xafffffff, 0x2ffffffe }, // Opt = 0 + { 0x0, 0x3ff0000, 0x7fffffe, 0x7fffffe }, // Opt = 1 + { 0x0, 0x3ff0000, 0x7e, 0x7e }, // Opt = 2 + { 0x0, 0x3ffc000, 0x7fffffe, 0x7fffffe } // Opt = 3 + }; + + char *cOpt[4] = { "Any", "LetNum", "Hex", "Crypt" }; + + // Default option 0 + if (Opt < 0 || Opt > 3) { + Opt = 0; + if (gDebug > 2) + ErrorInfo("RpdGetRandString: Unknown option: %d : assume 0", Opt); + } + if (gDebug > 2) + ErrorInfo("RpdGetRandString: Enter ... Len: %d %s", Len, cOpt[Opt]); + + // Allocate buffer + char *Buf = new char[Len + 1]; + + // Get current time as seed for rand(). + time_t curtime; + time(&curtime); + int seed = (int) curtime; + + // feed seed + if (seed) + srand(seed); + + // randomize + int k = 0; + int i, j, l, m, frnd; + while (k < Len) { + frnd = rand(); + for (m = 7; m < 32; m += 7) { + i = 0x7F & (frnd >> m); + j = i / 32; + l = i - j * 32; + if ((iimx[Opt][j] & (1 << l))) { + Buf[k] = i; + k++; + } + if (k == Len) + break; + } + } + + // NULL terminated + Buf[Len] = 0; + if (gDebug > 2) + ErrorInfo("RpdGetRandString: got '%s' ", Buf); + + return Buf; +} + +//______________________________________________________________________________ +int RpdGetRSAKeys(char *PubKey, int Opt) +{ + // Get public key from file PubKey (Opt == 1) or string PubKey (Opt == 0). + + char Str[kMAXPATHLEN] = { 0 }; + int KeyType = 0; + + if (gDebug > 2) + ErrorInfo("RpdGetRSAKeys: enter: file opt '%s' %d ", PubKey, Opt); + + if (!PubKey) + return KeyType; + + FILE *fKey = 0; + // Parse input type + KeyType = 1; + if (Opt == 1) { + // Input is a File name: should get the string first + if (access(PubKey, R_OK)) { + ErrorInfo("RpdGetRSAKeys: Key File cannot be read - return "); + return 0; + } + fKey = fopen(PubKey, "r"); + if (!fKey) { + ErrorInfo("RpdGetRSAKeys: cannot open key file %s ", PubKey); + return 0; + } + fgets(Str, sizeof(Str), fKey); + } + + if (Opt == 0) { + strcpy(Str, PubKey); + } + if (strlen(Str) > 0) { + // The format is #<hex_n>#<hex_d># + char *pd1 = strstr(Str, "#"); + char *pd2 = strstr(pd1 + 1, "#"); + char *pd3 = strstr(pd2 + 1, "#"); + if (pd1 && pd2 && pd3) { + // Get <hex_n> ... + int l1 = (int) (pd2 - pd1 - 1); + char *RSA_n_exp = new char[l1 + 1]; + strncpy(RSA_n_exp, pd1 + 1, l1); + RSA_n_exp[l1] = 0; + if (gDebug > 2) + ErrorInfo("RpdGetRSAKeys: got RSA_n_exp '%s' ", RSA_n_exp); + // Now <hex_d> + int l2 = (int) (pd3 - pd2 - 1); + char *RSA_d_exp = new char[l2 + 1]; + strncpy(RSA_d_exp, pd2 + 1, l2); + RSA_d_exp[l2] = 0; + if (gDebug > 2) + ErrorInfo("RpdGetRSAKeys: got RSA_d_exp '%s' ", RSA_d_exp); + + rsa_num_sget(&gRSA_n, RSA_n_exp); + rsa_num_sget(&gRSA_d, RSA_d_exp); + + if (RSA_n_exp) + SafeDelete(RSA_n_exp); + if (RSA_d_exp) + SafeDelete(RSA_d_exp); + + } else + return 0; + } + + if (fKey) + fclose(fKey); + + return KeyType; + +} + +//______________________________________________________________________________ +void RpdSavePubKey(char *PubKey, int OffSet) +{ + // Save RSA public key into file for later use by other rootd/proofd. + + if (gRSAKey == 0) + return; + + char PubKeyFile[kMAXPATHLEN]; + sprintf(PubKeyFile, "%s/rpk_%d", gTmpDir, OffSet); + FILE *fKey = fopen(PubKeyFile, "w"); + if (fKey) { + if (gRSAKey == 1) { + fprintf(fKey, "%s", PubKey); + } + } else { + ErrorInfo + ("RpdSavePubKey: cannot save public key: set entry inactive"); + RpdCleanupAuthTab(gOpenHost, gRemPid); + } + + if (fKey) { + fclose(fKey); + chmod(PubKeyFile, 0666); + } +} + +//______________________________________________________________________________ +int RpdSecureSend(char *Str) +{ + // Encode null terminated Str using the session private key indcated by Key + // and sends it over the network. + // Returns number of bytes sent.or -1 in case of error. + + char BufTmp[kMAXSECBUF]; + char BufLen[20]; + + int sLen = strlen(Str) + 1; + + int Ttmp = 0; + int Nsen = -1; + + if (gRSAKey == 1) { + strncpy(BufTmp, Str, sLen); + BufTmp[sLen] = 0; + Ttmp = rsa_encode(BufTmp, sLen, gRSA_n, gRSA_d); + sprintf(BufLen, "%d", Ttmp); + NetSend(BufLen, kROOTD_ENCRYPT); + Nsen = NetSendRaw(BufTmp, Ttmp); + if (gDebug > 4) + ErrorInfo + ("RpdSecureSend: Local: sent %d bytes (expected: %d) (buffer '%s')", + Nsen, Ttmp, BufTmp); + } else { + ErrorInfo("RpdSecureSend: Unknown key option (%d) - return", + gRSAKey); + } + + return Nsen; + +} + +//______________________________________________________________________________ +int RpdSecureRecv(char **Str) +{ + // Receive buffer and decode it in Str using key indicated by Key type. + // Return number of received bytes or -1 in case of error. + + char BufTmp[kMAXSECBUF]; + char BufLen[20]; + + int Nrec = -1; + // We must get a pointer ... + if (!Str) + return Nrec; + + if (gDebug > 2) + ErrorInfo("RpdSecureRecv: enter ... (key is %d)", gRSAKey); + + EMessageTypes kind; + NetRecv(BufLen, 20, kind); + int Len = atoi(BufLen); + if (gDebug > 4) + ErrorInfo("RpdSecureRecv: got len '%s' %d ", BufLen, Len); + if (!strncmp(BufLen, "-1", 2)) + return Nrec; + + // Now proceed + if (gRSAKey == 1) { + Nrec = NetRecvRaw(BufTmp, Len); + rsa_decode(BufTmp, Len, gRSA_n, gRSA_d); + if (gDebug > 2) + ErrorInfo("RpdSecureRecv: Local: decoded string: '%s' ", BufTmp); + } else { + ErrorInfo("RpdSecureRecv: Unknown key option (%d) - return", + gRSAKey); + } + + *Str = new char[strlen(BufTmp) + 1]; + strcpy(*Str, BufTmp); + + return Nrec; + +} + +} // namespace ROOT diff --git a/rpdutils/src/ssh.cxx b/rpdutils/src/ssh.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8f0a82888168085fa35032fe713eec14a6cdae2c --- /dev/null +++ b/rpdutils/src/ssh.cxx @@ -0,0 +1,248 @@ +// @(#)root/rpdutils:$Name: $:$Id: daemon.cxx,v 1.5 2002/10/28 14:22:51 rdm Exp $ +// Author: Gerardo Ganis 7/4/2003 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// // +// Set of utilities for rootd/proofd daemon SSH authentication. // +// // +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <sys/types.h> +#include <time.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> + +#if defined(linux) +# include <features.h> +# if __GNU_LIBRARY__ == 6 +# ifndef R__GLIBC +# define R__GLIBC +# endif +# endif +#endif +#if defined(__MACH__) && !defined(__APPLE__) +# define R__GLIBC +#endif + +#if defined(_AIX) || (defined(__FreeBSD__) && !defined(__alpha__)) +# define USE_SIZE_T +#elif defined(R__GLIBC) || (defined(__FreeBSD__) && defined(__alpha__)) +# define USE_SOCKLEN_T +#endif + +#include "rpdp.h" + +namespace ROOT { + +//--- Globals ------------------------------------------------------------------ +extern int gDebug; + + +//______________________________________________________________________________ +int SshToolAllocateSocket(unsigned int Uid, unsigned int Gid, char **pipe) +{ + // Allocates internal UNIX socket for SSH-like authentication. + // Sets socket ownership to user for later use. + // On success returns ID of allocated socket and related pipe, -1 otherwise. + + if (gDebug > 2) + ErrorInfo("SshToolAllocateSocket: enter: Uid:%d Gid:%d", Uid, Gid); + + // Open socket + int sd; + if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + ErrorInfo("SshToolAllocateSocket: error opening socket"); + return -1; + } + // Prepare binding ... + struct sockaddr_un servAddr; + servAddr.sun_family = AF_UNIX; + + // Determine unique pipe path: try with /tmp/rootdSSH_<random_string> + char fsun[] = "/tmp/rootdSSH_XXXXXXXX"; + mktemp(fsun); + if (gDebug > 2) + ErrorInfo("SshToolAllocateSocket: unique pipe name is %s", fsun); + + // Save path ... + strcpy(servAddr.sun_path, fsun); + + // bind to socket + if (bind(sd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) { + ErrorInfo("SshToolAllocateSocket: unable to bind to socket %d", sd); + return -1; + } + // Activate listening + if (listen(sd, 5)) { + ErrorInfo + ("SshToolAllocateSocket: can't activate listening (errno: %d)", + errno); + return -1; + } + + // Change ownerships and try to change them if needed + // This operaton is possible only as root ... but not always is needed + // so, do not stop in case of failure. + struct stat sst; + + // The socket ... + fstat(sd, &sst); + if (sst.st_uid != Uid || sst.st_gid != Gid) { + if (fchown(sd, Uid, Gid)) { + if (gDebug > 0) { + ErrorInfo + ("SshToolAllocateSocket: fchown: could not change socket %d ownership (errno= %d) ", + sd, errno); + ErrorInfo("SshToolAllocateSocket: socket (uid,gid) are: %d %d", + sst.st_uid, sst.st_gid); + ErrorInfo + ("SshToolAllocateSocket: may follow authentication problems"); + } + } + } + // The path ... + stat(fsun, &sst); + if (sst.st_uid != Uid || sst.st_gid != Gid) { + if (chown(fsun, Uid, Gid)) { + if (gDebug > 0) { + ErrorInfo + ("SshToolAllocateSocket: chown: could not change path '%s' ownership (errno= %d)", + fsun, errno); + ErrorInfo("SshToolAllocateSocket: path (uid,gid) are: %d %d", + sst.st_uid, sst.st_gid); + ErrorInfo + ("SshToolAllocateSocket: may follow authentication problems"); + } + } + } + // Fill output + *pipe = strdup(fsun); + + // return socket fd + return sd; +} + + +//______________________________________________________________________________ +void SshToolDiscardSocket(char *pipe, int sockfd) +{ + // Discards socket. + + if (gDebug > 2) + ErrorInfo + ("SshToolDiscardSocket: discarding socket: pipe: %s, fd: %d", + pipe, sockfd); + + // Unlink pipe + if (unlink(pipe) == -1) { + if (GetErrno() != ENOENT) { + ErrorInfo("SshToolDiscardSocket: unable to unlink %s" + "(errno: %d, ENOENT= %d)", pipe, GetErrno(), ENOENT); + } + } + // close socket + close(sockfd); +} + +//______________________________________________________________________________ +int SshToolNotifyFailure(char *Pipe) +{ + // Notifies failure of SSH authentication to relevant rootd/proofd process. + + if (gDebug > 2) + ErrorInfo("SshToolNotifyFailure: notifying failure to pipe %s\n", + Pipe); + + // Preparing socket connection + int sd; + struct sockaddr_un servAddr; + servAddr.sun_family = AF_UNIX; + strcpy(servAddr.sun_path, Pipe); + if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + ErrorInfo("SshToolNotifyFailure: cannot open socket: exiting "); + return 1; + } + // Connecting to socket + int rc; + if ((rc = + connect(sd, (struct sockaddr *) &servAddr, + sizeof(servAddr))) < 0) { + ErrorInfo("SshToolNotifyFailure: cannot connect socket: exiting "); + return 1; + } + // Sending "KO" ... + char *okbuf = "KO"; + rc = send(sd, okbuf, strlen(okbuf), 0); + if (rc != 2) { + ErrorInfo + ("SshToolNotifyFailure: sending might have been unsuccessful (bytes send: %d)", + rc); + } + + return 0; +} + +//______________________________________________________________________________ +int SshToolGetAuth(int UnixFd) +{ + int Auth = 0; + + if (gDebug > 2) + ErrorInfo("SshToolGetAuth: accepting connections on socket %d", + UnixFd); + + // Wait for verdict form sshd (via ssh2rpd ...) + struct sockaddr SunAddr; +#if defined(USE_SIZE_T) + size_t SunAddrLen = sizeof(SunAddr); +#elif defined(USE_SOCKLEN_T) + socklen_t SunAddrLen = sizeof(SunAddr); +#else + int SunAddrLen = sizeof(SunAddr); +#endif + int NewUnixFd = + accept(UnixFd, (struct sockaddr *) &SunAddr, &SunAddrLen); + + char SshAuth[2] = { 0 }; + int nr = NetRecvRaw(NewUnixFd, SshAuth, 2); + if (nr != 2) { + ErrorInfo + ("RootdSshAuth: incorrect reception from ssh2rpd: bytes:%d, buffer:%s ", + nr, SshAuth); + } + // Check authentication and notify to client + if (strncmp(SshAuth, "OK", 2) != 0) { + ErrorInfo("RootdSshAuth: user did not authenticate to sshd: %s (%d)", + SshAuth, strncmp(SshAuth, "OK", 2)); + } else { + Auth = 1; + } + + // Close local socket + close(NewUnixFd); + + return Auth; +} + +} // namespace ROOT