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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1884 - (show 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 /**
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