/[pdpsoft]/trunk/grid-mw-security/cgul/realpath/realpath.c
ViewVC logotype

Annotation of /trunk/grid-mw-security/cgul/realpath/realpath.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1884 - (hide annotations) (download) (as text)
Thu Aug 19 12:55:54 2010 UTC (11 years, 9 months ago) by msalle
Original Path: trunk/grid-mw-security/cgul/realpath/cgul_realpath.c
File MIME type: text/x-chdr
File size: 5399 byte(s)
Adding a substitute for the unsafe realpath() or unportable
canonicalize_file_name().
Note that it is NOT thread safe due to the chdir trick...


1 msalle 1884 /**
2     * Copyright (c) Members of the EGEE Collaboration. 2010.
3     * See http://www.eu-egee.org/partners/ for details on the copyright
4     * holders.
5     *
6     * Licensed under the Apache License, Version 2.0 (the "License");
7     * you may not use this file except in compliance with the License.
8     * You may obtain a copy of the License at
9     *
10     * http://www.apache.org/licenses/LICENSE-2.0
11     *
12     * Unless required by applicable law or agreed to in writing, software
13     * distributed under the License is distributed on an "AS IS" BASIS,
14     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15     * See the License for the specific language governing permissions and
16     * limitations under the License.
17     *
18     * Authors: Oscar Koeroo, Mischa Sall\'e, Aram Verstegen
19     * NIKHEF Amsterdam, the Netherlands
20     * <grid-mw-security@nikhef.nl>
21     */
22    
23     #include <stdio.h>
24     #include <stdlib.h>
25     #include <string.h>
26     #include <unistd.h>
27     #include <fcntl.h>
28     #include <limits.h>
29     #include <sys/types.h>
30     #include <sys/stat.h>
31     #include <errno.h>
32    
33     /* Make sure at least internally we have a PATH_MAX */
34     #ifndef PATH_MAX
35     #define PATH_MAX 1024
36     #endif
37    
38     /* Make sure at least internally we have a SYMLOOP_MAX */
39     #ifndef SYMLOOP_MAX
40     #define SYMLOOP_MAX _POSIX_SYMLOOP_MAX
41     #endif
42    
43     /*!
44     * Returns the fully canonicalized and absolute path for a diretory or NULL on
45     * error. Memory for the return string is malloced and should be freed by the
46     * caller. Any path cannot be longer than PATH_MAX. Note that it is necessary
47     * that we can chdir to dir.
48     * NOTE: This function is not thread-safe
49     * \param dir non-absolute and/or non-canonical directory
50     * \return canonical absolute directory
51     */
52     char *cgul_realdir(const char *dir) {
53     int olddir;
54     char buf[PATH_MAX],*path;
55    
56     /* Safe old dir and then go to the new one */
57     if ( (olddir=open(".",O_RDONLY))==-1 ||
58     chdir(dir)==-1 )
59     return NULL;
60     /* Get the location, don't exit yet when failed: need to go back */
61     path=getcwd(buf,PATH_MAX);
62     /* Go back, note that it's really bad if this fails! */
63     if ( fchdir(olddir) ||
64     close(olddir) )
65     return NULL;
66     /* Make a copy */
67     if (path)
68     path=strdup(buf);
69    
70     return path;
71     }
72    
73     /*!
74     * Returns the fully canonicalized and absolute path for any path or NULL on
75     * error. Note that this function substitutes the unsafe realpath() or the
76     * GNU-only canonicalize_file_name().
77     * Memory for the return string is malloced and should be freed by the
78     * caller. Any path cannot be longer than PATH_MAX. Any directory has to be
79     * accessible, including if it's the last element.
80     * NOTE: This function is not thread-safe
81     * \param inpath non-absolute and/or non-canonical path
82     * \param instat optional stat information on the input (for performance, if
83     * already available). When NULL it will be determined locally
84     * when needed.
85     * \return canonical absolute path
86     */
87     char *cgul_realpath(const char *inpath, struct stat *instat) {
88     char buf[PATH_MAX], path[PATH_MAX];
89     char *pos,*canonicdir;
90     int pathlen,filelen,linklen, linkcount=0;
91     struct stat st;
92    
93     /* Check and store the length of the input (incl \0) */
94     if ( (pathlen=1+strlen(inpath)) > PATH_MAX) {
95     errno=ENAMETOOLONG;
96     return NULL;
97     }
98     /* Check last compo is dir: then just return realdir() */
99     if (instat==NULL) {
100     if (stat(inpath, &st)==-1) /* Error */
101     return NULL;
102     instat=&st;
103     }
104     if (S_ISDIR(instat->st_mode))
105     return cgul_realdir(inpath);
106    
107     /* Make path absolute */
108     if (inpath[0]!='/') { /* relative */
109     /* get and add cwd */
110     if (!getcwd(buf,PATH_MAX)) {
111     if (errno==ERANGE) errno=ENAMETOOLONG;
112     return NULL;
113     }
114     if ( (pathlen=snprintf(path,PATH_MAX,"%s/%s",buf,inpath))>PATH_MAX ) {
115     errno=ENAMETOOLONG;
116     return NULL;
117     }
118     } else /* absolute */
119     strcpy(path,inpath);
120    
121     /* Now loop over symlink, if any */
122     /* readlink wants buffersize without \0: PATH_MAX-1 */
123     while ( (linklen=readlink(path,buf,PATH_MAX-1)) != -1 ) {
124     if (++linkcount > SYMLOOP_MAX) { /* Too many symlinks */
125     errno=ELOOP;
126     return NULL;
127     }
128     buf[linklen]='\0';
129     /* Check the symlink */
130     if (buf[0]=='/') /* absolute: replaces entire path */
131     strcpy(path,buf);
132     else { /* relative: replaces last component */
133     pos=strrchr(path,'/'); /* Has to exist, we made it absolute */
134     filelen=strlen(pos+1); /* length of remainder without \0 */
135     /* Note: pathlen is with \0, filelen and linklen without, hence
136     * combined as follows is with \0 and should be <= PATH_MAX */
137     if (pathlen-filelen+linklen>PATH_MAX) {
138     errno=ENAMETOOLONG;
139     return NULL;
140     }
141     strcpy(pos+1,buf); /* It fits, so use strcpy */
142     }
143     }
144     /* Alway end due to realink: check it's due to non-symlink */
145     if (errno!=EINVAL) /* i.e. other error */
146     return NULL;
147    
148     /* Now path is not a symlink */
149    
150     /* Find dir part */
151     pos=strrchr(path,'/'); /* Has to exist, we made it absolute */
152     /* dir: up to pos, file: pos+1 till end */
153     pos[0]='\0';
154     canonicdir=cgul_realdir(path);
155     pos[0]='/'; /* Clean but unnecessary */
156     /* Put them together, canonicdir doesn't end with a / */
157     pathlen=snprintf(buf,PATH_MAX,"%s/%s",canonicdir,pos+1);
158     free(canonicdir); /* Done with canonicdir */
159     if (pathlen>PATH_MAX) {
160     errno=ENAMETOOLONG;
161     return NULL;
162     }
163    
164     /* Return duplicate, or NULL when fails */
165     return strdup(buf);
166     }

grid.support@nikhef.nl
ViewVC Help
Powered by ViewVC 1.1.28