Imported Upstream version 1.2.3
[nfs-utils.git] / utils / mountd / rmtab.c
1 /*
2  * utils/mountd/rmtab.c
3  *
4  * Manage the rmtab file for mountd.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <netdb.h>
19
20 #include "misc.h"
21 #include "exportfs.h"
22 #include "xio.h"
23 #include "mountd.h"
24 #include "ha-callout.h"
25
26 #include <limits.h> /* PATH_MAX */
27 #include <errno.h>
28
29 extern int reverse_resolve;
30
31 /* If new path is a link do not destroy it but place the
32  * file where the link points.
33  */
34
35 static int 
36 slink_safe_rename(const char * oldpath, const char * newpath)
37 {
38         int r;
39         struct stat s;
40         char slink_path[PATH_MAX];
41         const char *real_newpath = newpath;
42
43         if ((lstat(newpath, &s) == 0) && S_ISLNK(s.st_mode)) {
44                 /* New path is a symbolic link, do not destroy but follow */
45                 if ((r = readlink(newpath, slink_path, PATH_MAX - 1)) == -1)
46                         return -1;
47                 slink_path[r] = '\0';
48                 real_newpath = slink_path;
49         }
50
51         return rename(oldpath, real_newpath);
52 }
53
54 void
55 mountlist_add(char *host, const char *path)
56 {
57         struct rmtabent xe;
58         struct rmtabent *rep;
59         int             lockid;
60         long            pos;
61
62         if ((lockid = xflock(_PATH_RMTABLCK, "a")) < 0)
63                 return;
64         setrmtabent("r+");
65         while ((rep = getrmtabent(1, &pos)) != NULL) {
66                 if (strcmp (rep->r_client,
67                             host) == 0
68                     && strcmp(rep->r_path, path) == 0) {
69                         rep->r_count++;
70                         /* PRC: do the HA callout: */
71                         ha_callout("mount", rep->r_client, rep->r_path, rep->r_count);
72                         putrmtabent(rep, &pos);
73                         endrmtabent();
74                         xfunlock(lockid);
75                         return;
76                 }
77         }
78         endrmtabent();
79         strncpy(xe.r_client, host,
80                 sizeof (xe.r_client) - 1);
81         xe.r_client [sizeof (xe.r_client) - 1] = '\0';
82         strncpy(xe.r_path, path, sizeof (xe.r_path) - 1);
83         xe.r_path [sizeof (xe.r_path) - 1] = '\0';
84         xe.r_count = 1;
85         if (setrmtabent("a")) {
86                 /* PRC: do the HA callout: */
87                 ha_callout("mount", xe.r_client, xe.r_path, xe.r_count);
88                 putrmtabent(&xe, NULL);
89                 endrmtabent();
90         }
91         xfunlock(lockid);
92 }
93
94 void
95 mountlist_del(char *hname, const char *path)
96 {
97         struct rmtabent *rep;
98         FILE            *fp;
99         int             lockid;
100         int             match;
101
102         if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
103                 return;
104         if (!setrmtabent("r")) {
105                 xfunlock(lockid);
106                 return;
107         }
108         if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) {
109                 endrmtabent();
110                 xfunlock(lockid);
111                 return;
112         }
113         while ((rep = getrmtabent(1, NULL)) != NULL) {
114                 match = !strcmp (rep->r_client, hname)
115                         && !strcmp(rep->r_path, path);
116                 if (match) {
117                         rep->r_count--;
118                         /* PRC: do the HA callout: */
119                         ha_callout("unmount", rep->r_client, rep->r_path, rep->r_count);
120                 }
121                 if (!match || rep->r_count)
122                         fputrmtabent(fp, rep, NULL);
123         }
124         if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
125                 xlog(L_ERROR, "couldn't rename %s to %s",
126                                 _PATH_RMTABTMP, _PATH_RMTAB);
127         }
128         endrmtabent();  /* close & unlink */
129         fendrmtabent(fp);
130         xfunlock(lockid);
131 }
132
133 void
134 mountlist_del_all(const struct sockaddr *sap)
135 {
136         char            *hostname;
137         struct rmtabent *rep;
138         FILE            *fp;
139         int             lockid;
140
141         if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
142                 return;
143         hostname = host_canonname(sap);
144         if (hostname == NULL) {
145                 char buf[INET6_ADDRSTRLEN];
146                 xlog(L_ERROR, "can't get hostname of %s",
147                         host_ntop(sap, buf, sizeof(buf)));
148                 goto out_unlock;
149         }
150
151         if (!setrmtabent("r"))
152                 goto out_free;
153
154         if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w")))
155                 goto out_close;
156
157         while ((rep = getrmtabent(1, NULL)) != NULL) {
158                 if (strcmp(rep->r_client, hostname) == 0 &&
159                     auth_authenticate("umountall", sap, rep->r_path) != NULL)
160                         continue;
161                 fputrmtabent(fp, rep, NULL);
162         }
163         if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
164                 xlog(L_ERROR, "couldn't rename %s to %s",
165                                 _PATH_RMTABTMP, _PATH_RMTAB);
166         }
167         fendrmtabent(fp);
168 out_close:
169         endrmtabent();  /* close & unlink */
170 out_free:
171         free(hostname);
172 out_unlock:
173         xfunlock(lockid);
174 }
175
176 static void
177 mountlist_freeall(mountlist list)
178 {
179         while (list != NULL) {
180                 mountlist m = list;
181                 list = m->ml_next;
182                 free(m->ml_hostname);
183                 free(m->ml_directory);
184                 free(m);
185         }
186 }
187
188 mountlist
189 mountlist_list(void)
190 {
191         static mountlist        mlist = NULL;
192         static time_t           last_mtime = 0;
193         mountlist               m;
194         struct rmtabent         *rep;
195         struct stat             stb;
196         int                     lockid;
197
198         if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
199                 return NULL;
200         if (stat(_PATH_RMTAB, &stb) < 0) {
201                 xlog(L_ERROR, "can't stat %s: %s",
202                                 _PATH_RMTAB, strerror(errno));
203                 xfunlock(lockid);
204                 return NULL;
205         }
206         if (stb.st_mtime != last_mtime) {
207                 mountlist_freeall(mlist);
208                 last_mtime = stb.st_mtime;
209
210                 setrmtabent("r");
211                 while ((rep = getrmtabent(1, NULL)) != NULL) {
212                         m = calloc(1, sizeof(*m));
213                         if (m == NULL) {
214                                 mountlist_freeall(mlist);
215                                 mlist = NULL;
216                                 xlog(L_ERROR, "%s: memory allocation failed",
217                                                 __func__);
218                                 break;
219                         }
220
221                         if (reverse_resolve) {
222                                 struct addrinfo *ai;
223                                 ai = host_pton(rep->r_client);
224                                 if (ai != NULL) {
225                                         m->ml_hostname = host_canonname(ai->ai_addr);
226                                         freeaddrinfo(ai);
227                                 }
228                         }
229                         if (m->ml_hostname == NULL)
230                                 m->ml_hostname = strdup(rep->r_client);
231
232                         m->ml_directory = strdup(rep->r_path);
233
234                         if (m->ml_hostname == NULL || m->ml_directory == NULL) {
235                                 mountlist_freeall(mlist);
236                                 mlist = NULL;
237                                 xlog(L_ERROR, "%s: memory allocation failed",
238                                                 __func__);
239                                 break;
240                         }
241
242                         m->ml_next = mlist;
243                         mlist = m;
244                 }
245                 endrmtabent();
246         }
247         xfunlock(lockid);
248
249         return mlist;
250 }