~ubuntu-branches/ubuntu/hardy/nfs-utils/hardy-security

« back to all changes in this revision

Viewing changes to utils/mount/nfs4mount.c

  • Committer: Bazaar Package Importer
  • Author(s): Steinar H. Gunderson
  • Date: 2006-07-04 18:55:51 UTC
  • mfrom: (1.2.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060704185551-nretm3mbb84cyh2g
Tags: 1:1.0.8+1.0.9pre1-1
* New upstream release.
  * debian/ directory removed from upstream; no need to repack or do ugly
    hacks in debian/rules anymore.
  * Obsoletes most Debian-specific patches, as they are already included
    upstream. For reference, the patches that are still Debian-specific are:
    * Use 65534 instead of -2 for anonuid, update manpage accordingly.
    * Debian-specific information in exports man page.
    * Don't use -rpath for gssd.
    * Hardcode default mapping in svcgssd. Adjust patch to use uid/gid 
      65534 instead of -2, for consistency; also remove double error
      message. 
    * Spelling fixes in nfsstat, showmount and statd man pages.
  * Supports options to bind to specific IPs. (Closes: #246939, #312720)
  * Include mount.nfs and friends, which will over time take over the job of
    doing NFS mounting from util-linux.
* Complete sync with Ubuntu:
  * Pull in changes to use LSB display functions in init scripts; adapted
    to give output more like what was already in Debian, to fix a few bugs,
    and use plain echo in "status" targets, where using LSB functions makes
    no sense.
  * Depend on lsb-base from nfs-common and nfs-kernel-server.
* Init script updates:
  * Document "status" option in the nfs-common init script's help message.
  * Drop "set -e"; it makes error checking wrt. the LSB functions harder.
  * Drop obsolete "cd /".
  * Fix syntax errors in "status" target.
  * In the "status" target, don't check that the output of pidof matches the
    pidfiles for gssd and idmapd, as they fork after start and thus get a
    different pid.
* Include gss_clnt_send_err and gss_destroy_creds binaries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * nfs4mount.c -- Linux NFS mount
 
3
 * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2, or (at your option)
 
8
 * any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * Note: this file based on the original nfsmount.c
 
16
 *
 
17
 * 2006-06-06 Amit Gud <agud@redhat.com>
 
18
 * - Moved to nfs-utils/utils/mount from util-linux/mount.
 
19
 */
 
20
 
 
21
#include <unistd.h>
 
22
#include <stdio.h>
 
23
#include <string.h>
 
24
#include <errno.h>
 
25
#include <netdb.h>
 
26
#include <time.h>
 
27
#include <sys/stat.h>
 
28
#include <netinet/in.h>
 
29
#include <arpa/inet.h>
 
30
#include <rpc/auth.h>
 
31
#include <rpc/rpc.h>
 
32
#ifdef HAVE_RPCSVC_NFS_PROT_H
 
33
#include <rpcsvc/nfs_prot.h>
 
34
#else
 
35
#include <linux/nfs.h>
 
36
#define nfsstat nfs_stat
 
37
#endif
 
38
 
 
39
#include "nls.h"
 
40
#include "conn.h"
 
41
#include "xcommon.h"
 
42
 
 
43
#include "nfs4_mount.h"
 
44
#include "nfs_mount.h"
 
45
 
 
46
#if defined(VAR_LOCK_DIR)
 
47
#define DEFAULT_DIR VAR_LOCK_DIR
 
48
#else
 
49
#define DEFAULT_DIR "/var/lock/subsys"
 
50
#endif
 
51
 
 
52
extern int verbose;
 
53
 
 
54
char *IDMAPLCK = DEFAULT_DIR "/rpcidmapd";
 
55
#define idmapd_check() do { \
 
56
        if (access(IDMAPLCK, F_OK)) { \
 
57
                printf(_("Warning: rpc.idmapd appears not to be running.\n" \
 
58
                        "         All uids will be mapped to the nobody uid.\n")); \
 
59
        } \
 
60
} while(0);
 
61
 
 
62
char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
 
63
#define gssd_check() do { \
 
64
                if (access(GSSDLCK, F_OK)) { \
 
65
                        printf(_("Warning: rpc.gssd appears not to be running.\n")); \
 
66
                } \
 
67
} while(0); 
 
68
 
 
69
#ifndef NFS_PORT
 
70
#define NFS_PORT 2049
 
71
#endif
 
72
 
 
73
struct {
 
74
        char    *flavour;
 
75
        int     fnum;
 
76
} flav_map[] = {
 
77
        { "krb5",       RPC_AUTH_GSS_KRB5       },
 
78
        { "krb5i",      RPC_AUTH_GSS_KRB5I      },
 
79
        { "krb5p",      RPC_AUTH_GSS_KRB5P      },
 
80
        { "lipkey",     RPC_AUTH_GSS_LKEY       },
 
81
        { "lipkey-i",   RPC_AUTH_GSS_LKEYI      },
 
82
        { "lipkey-p",   RPC_AUTH_GSS_LKEYP      },
 
83
        { "spkm3",      RPC_AUTH_GSS_SPKM       },
 
84
        { "spkm3i",     RPC_AUTH_GSS_SPKMI      },
 
85
        { "spkm3p",     RPC_AUTH_GSS_SPKMP      },
 
86
        { "unix",       AUTH_UNIX               },
 
87
        { "sys",        AUTH_SYS                },
 
88
        { "null",       AUTH_NULL               },
 
89
        { "none",       AUTH_NONE               },
 
90
};
 
91
 
 
92
#define FMAPSIZE                (sizeof(flav_map)/sizeof(flav_map[0]))
 
93
#define MAX_USER_FLAVOUR        16
 
94
 
 
95
static int parse_sec(char *sec, int *pseudoflavour)
 
96
{
 
97
        int i, num_flavour = 0;
 
98
 
 
99
        for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
 
100
                if (num_flavour >= MAX_USER_FLAVOUR) {
 
101
                        fprintf(stderr,
 
102
                                _("mount: maximum number of security flavors "
 
103
                                  "exceeded\n"));
 
104
                        return 0;
 
105
                }
 
106
                for (i = 0; i < FMAPSIZE; i++) {
 
107
                        if (strcmp(sec, flav_map[i].flavour) == 0) {
 
108
                                pseudoflavour[num_flavour++] = flav_map[i].fnum;
 
109
                                break;
 
110
                        }
 
111
                }
 
112
                if (i == FMAPSIZE) {
 
113
                        fprintf(stderr,
 
114
                                _("mount: unknown security type %s\n"), sec);
 
115
                        return 0;
 
116
                }
 
117
        }
 
118
        if (!num_flavour)
 
119
                fprintf(stderr,
 
120
                        _("mount: no security flavors passed to sec= option\n"));
 
121
        return num_flavour;
 
122
}
 
123
 
 
124
static int parse_devname(char *hostdir, char **hostname, char **dirname)
 
125
{
 
126
        char *s;
 
127
 
 
128
        if (!(s = strchr(hostdir, ':'))) {
 
129
                fprintf(stderr,
 
130
                        _("mount: "
 
131
                          "directory to mount not in host:dir format\n"));
 
132
                return -1;
 
133
        }
 
134
        *hostname = hostdir;
 
135
        *dirname = s + 1;
 
136
        *s = '\0';
 
137
        /* Ignore all but first hostname in replicated mounts
 
138
           until they can be fully supported. (mack@sgi.com) */
 
139
        if ((s = strchr(hostdir, ','))) {
 
140
                *s = '\0';
 
141
                fprintf(stderr,
 
142
                        _("mount: warning: "
 
143
                          "multiple hostnames not supported\n"));
 
144
        }
 
145
        return 0;
 
146
}
 
147
 
 
148
static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
 
149
{
 
150
        struct hostent *hp;
 
151
        addr->sin_family = AF_INET;
 
152
 
 
153
        if (inet_aton(hostname, &addr->sin_addr))
 
154
                return 0;
 
155
        if ((hp = gethostbyname(hostname)) == NULL) {
 
156
                fprintf(stderr, _("mount: can't get address for %s\n"),
 
157
                        hostname);
 
158
                return -1;
 
159
        }
 
160
        if (hp->h_length > sizeof(struct in_addr)) {
 
161
                fprintf(stderr,
 
162
                        _("mount: got bad hp->h_length\n"));
 
163
                hp->h_length = sizeof(struct in_addr);
 
164
        }
 
165
        memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
 
166
        return 0;
 
167
}
 
168
 
 
169
static int get_my_ipv4addr(char *ip_addr, int len)
 
170
{
 
171
        char myname[1024];
 
172
        struct sockaddr_in myaddr;
 
173
 
 
174
        if (gethostname(myname, sizeof(myname))) {
 
175
                fprintf(stderr, _("mount: can't determine client address\n"));
 
176
                return -1;
 
177
        }
 
178
        if (fill_ipv4_sockaddr(myname, &myaddr))
 
179
                return -1;
 
180
        snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
 
181
        ip_addr[len-1] = '\0';
 
182
        return 0;
 
183
}
 
184
 
 
185
int nfs4mount(const char *spec, const char *node, int *flags,
 
186
              char **extra_opts, char **mount_opts,
 
187
              int running_bg)
 
188
{
 
189
        static struct nfs4_mount_data data;
 
190
        static char hostdir[1024];
 
191
        static char ip_addr[16] = "127.0.0.1";
 
192
        static struct sockaddr_in server_addr, client_addr;
 
193
        static int pseudoflavour[MAX_USER_FLAVOUR];
 
194
        int num_flavour = 0;
 
195
        int ip_addr_in_opts = 0;
 
196
 
 
197
        char *hostname, *dirname, *old_opts;
 
198
        char new_opts[1024];
 
199
        char *opt, *opteq;
 
200
        char *s;
 
201
        int val;
 
202
        int bg, soft, intr;
 
203
        int nocto, noac;
 
204
        int retry;
 
205
        int retval;
 
206
        time_t timeout, t;
 
207
 
 
208
        retval = EX_FAIL;
 
209
        if (strlen(spec) >= sizeof(hostdir)) {
 
210
                fprintf(stderr, _("mount: "
 
211
                                  "excessively long host:dir argument\n"));
 
212
                goto fail;
 
213
        }
 
214
        strcpy(hostdir, spec);
 
215
        if (parse_devname(hostdir, &hostname, &dirname))
 
216
                goto fail;
 
217
 
 
218
        if (fill_ipv4_sockaddr(hostname, &server_addr))
 
219
                goto fail;
 
220
        if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
 
221
                goto fail;
 
222
 
 
223
        /* add IP address to mtab options for use when unmounting */
 
224
        s = inet_ntoa(server_addr.sin_addr);
 
225
        old_opts = *extra_opts;
 
226
        if (!old_opts)
 
227
                old_opts = "";
 
228
        if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
 
229
                fprintf(stderr, _("mount: "
 
230
                                  "excessively long option argument\n"));
 
231
                goto fail;
 
232
        }
 
233
        snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
 
234
                 old_opts, *old_opts ? "," : "", s);
 
235
        *extra_opts = xstrdup(new_opts);
 
236
 
 
237
        /* Set default options.
 
238
         * rsize/wsize and timeo are left 0 in order to
 
239
         * let the kernel decide.
 
240
         */
 
241
        memset(&data, 0, sizeof(data));
 
242
        data.retrans    = 3;
 
243
        data.acregmin   = 3;
 
244
        data.acregmax   = 60;
 
245
        data.acdirmin   = 30;
 
246
        data.acdirmax   = 60;
 
247
        data.proto      = IPPROTO_TCP;
 
248
 
 
249
        bg = 0;
 
250
        soft = 0;
 
251
        intr = NFS4_MOUNT_INTR;
 
252
        nocto = 0;
 
253
        noac = 0;
 
254
        retry = 10000;          /* 10000 minutes ~ 1 week */
 
255
 
 
256
        /*
 
257
         * NFSv4 specifies that the default port should be 2049
 
258
         */
 
259
        server_addr.sin_port = htons(NFS_PORT);
 
260
 
 
261
        /* parse options */
 
262
 
 
263
        for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
 
264
                if ((opteq = strchr(opt, '='))) {
 
265
                        val = atoi(opteq + 1);  
 
266
                        *opteq = '\0';
 
267
                        if (!strcmp(opt, "rsize"))
 
268
                                data.rsize = val;
 
269
                        else if (!strcmp(opt, "wsize"))
 
270
                                data.wsize = val;
 
271
                        else if (!strcmp(opt, "timeo"))
 
272
                                data.timeo = val;
 
273
                        else if (!strcmp(opt, "retrans"))
 
274
                                data.retrans = val;
 
275
                        else if (!strcmp(opt, "acregmin"))
 
276
                                data.acregmin = val;
 
277
                        else if (!strcmp(opt, "acregmax"))
 
278
                                data.acregmax = val;
 
279
                        else if (!strcmp(opt, "acdirmin"))
 
280
                                data.acdirmin = val;
 
281
                        else if (!strcmp(opt, "acdirmax"))
 
282
                                data.acdirmax = val;
 
283
                        else if (!strcmp(opt, "actimeo")) {
 
284
                                data.acregmin = val;
 
285
                                data.acregmax = val;
 
286
                                data.acdirmin = val;
 
287
                                data.acdirmax = val;
 
288
                        }
 
289
                        else if (!strcmp(opt, "retry"))
 
290
                                retry = val;
 
291
                        else if (!strcmp(opt, "port"))
 
292
                                server_addr.sin_port = htons(val);
 
293
                        else if (!strcmp(opt, "proto")) {
 
294
                                if (!strncmp(opteq+1, "tcp", 3))
 
295
                                        data.proto = IPPROTO_TCP;
 
296
                                else if (!strncmp(opteq+1, "udp", 3))
 
297
                                        data.proto = IPPROTO_UDP;
 
298
                                else
 
299
                                        printf(_("Warning: Unrecognized proto= option.\n"));
 
300
                        } else if (!strcmp(opt, "clientaddr")) {
 
301
                                if (strlen(opteq+1) >= sizeof(ip_addr))
 
302
                                        printf(_("Invalid client address %s"),
 
303
                                                                opteq+1);
 
304
                                strncpy(ip_addr,opteq+1, sizeof(ip_addr));
 
305
                                ip_addr[sizeof(ip_addr)-1] = '\0';
 
306
                                ip_addr_in_opts = 1;
 
307
                        } else if (!strcmp(opt, "sec")) {
 
308
                                num_flavour = parse_sec(opteq+1, pseudoflavour);
 
309
                                if (!num_flavour)
 
310
                                        goto fail;
 
311
                        } else if (!strcmp(opt, "addr")) {
 
312
                                /* ignore */;
 
313
                        } else {
 
314
                                printf(_("unknown nfs mount parameter: "
 
315
                                         "%s=%d\n"), opt, val);
 
316
                                goto fail;
 
317
                        }
 
318
                } else {
 
319
                        val = 1;
 
320
                        if (!strncmp(opt, "no", 2)) {
 
321
                                val = 0;
 
322
                                opt += 2;
 
323
                        }
 
324
                        if (!strcmp(opt, "bg")) 
 
325
                                bg = val;
 
326
                        else if (!strcmp(opt, "fg")) 
 
327
                                bg = !val;
 
328
                        else if (!strcmp(opt, "soft"))
 
329
                                soft = val;
 
330
                        else if (!strcmp(opt, "hard"))
 
331
                                soft = !val;
 
332
                        else if (!strcmp(opt, "intr"))
 
333
                                intr = val;
 
334
                        else if (!strcmp(opt, "cto"))
 
335
                                nocto = !val;
 
336
                        else if (!strcmp(opt, "ac"))
 
337
                                noac = !val;
 
338
                        else {
 
339
                                printf(_("unknown nfs mount option: "
 
340
                                         "%s%s\n"), val ? "" : "no", opt);
 
341
                                goto fail;
 
342
                        }
 
343
                }
 
344
        }
 
345
 
 
346
        data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
 
347
                | (intr ? NFS4_MOUNT_INTR : 0)
 
348
                | (nocto ? NFS4_MOUNT_NOCTO : 0)
 
349
                | (noac ? NFS4_MOUNT_NOAC : 0);
 
350
 
 
351
        /*
 
352
         * Give a warning if the rpc.idmapd daemon is not running
 
353
         */
 
354
        idmapd_check();
 
355
 
 
356
        if (num_flavour == 0)
 
357
                pseudoflavour[num_flavour++] = AUTH_UNIX;
 
358
        else {
 
359
                /*
 
360
                 * ditto with rpc.gssd daemon
 
361
                 */
 
362
                gssd_check();
 
363
        }
 
364
        data.auth_flavourlen = num_flavour;
 
365
        data.auth_flavours = pseudoflavour;
 
366
 
 
367
        data.client_addr.data = ip_addr;
 
368
        data.client_addr.len = strlen(ip_addr);
 
369
 
 
370
        data.mnt_path.data = dirname;
 
371
        data.mnt_path.len = strlen(dirname);
 
372
 
 
373
        data.hostname.data = hostname;
 
374
        data.hostname.len = strlen(hostname);
 
375
        data.host_addr = (struct sockaddr *)&server_addr;
 
376
        data.host_addrlen = sizeof(server_addr);
 
377
 
 
378
#ifdef NFS_MOUNT_DEBUG
 
379
        printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
 
380
               data.rsize, data.wsize, data.timeo, data.retrans);
 
381
        printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
 
382
               data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
 
383
        printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
 
384
               ntohs(server_addr.sin_port), bg, retry, data.flags);
 
385
        printf("soft = %d, intr = %d, nocto = %d, noac = %d\n",
 
386
               (data.flags & NFS4_MOUNT_SOFT) != 0,
 
387
               (data.flags & NFS4_MOUNT_INTR) != 0,
 
388
               (data.flags & NFS4_MOUNT_NOCTO) != 0,
 
389
               (data.flags & NFS4_MOUNT_NOAC) != 0);
 
390
 
 
391
        if (num_flavour > 0) {
 
392
                int pf_cnt, i;
 
393
 
 
394
                printf("sec = ");
 
395
                for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
 
396
                        for (i = 0; i < FMAPSIZE; i++) {
 
397
                                if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
 
398
                                        printf("%s", flav_map[i].flavour);
 
399
                                        break;
 
400
                                }
 
401
                        }
 
402
                        printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
 
403
                }
 
404
        }
 
405
        printf("proto = %s\n", (data.proto == IPPROTO_TCP) ? "tcp" : "udp");
 
406
#endif
 
407
 
 
408
        timeout = time(NULL) + 60 * retry;
 
409
        data.version = NFS4_MOUNT_VERSION;
 
410
        for (;;) {
 
411
                if (verbose) {
 
412
                        fprintf(stderr, 
 
413
                                "mount: pinging: prog %d vers %d prot %s port %d\n", 
 
414
                                NFS_PROGRAM, 4, data.proto == IPPROTO_UDP ? "udp" : "tcp", 
 
415
                                ntohs(server_addr.sin_port));
 
416
                }
 
417
                client_addr.sin_family = 0;
 
418
                client_addr.sin_addr.s_addr = 0;
 
419
                clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto, &client_addr);
 
420
                if (rpc_createerr.cf_stat == RPC_SUCCESS) {
 
421
                        if (!ip_addr_in_opts &&
 
422
                            client_addr.sin_family != 0 &&
 
423
                            client_addr.sin_addr.s_addr != 0) {
 
424
                                snprintf(ip_addr, sizeof(ip_addr), "%s",
 
425
                                         inet_ntoa(client_addr.sin_addr));
 
426
                                data.client_addr.len = strlen(ip_addr);
 
427
                        }
 
428
                        break;
 
429
                }
 
430
 
 
431
                switch(rpc_createerr.cf_stat){
 
432
                case RPC_TIMEDOUT:
 
433
                        break;
 
434
                case RPC_SYSTEMERROR:
 
435
                        if (errno == ETIMEDOUT)
 
436
                                break;
 
437
                default:
 
438
                        mount_errors(hostname, 0, bg);
 
439
                        goto fail;
 
440
                }
 
441
                t = time(NULL);
 
442
                if (t >= timeout) {
 
443
                        mount_errors(hostname, 0, bg);
 
444
                        goto fail;
 
445
                }
 
446
                mount_errors(hostname, 1, bg);
 
447
                continue;
 
448
        }
 
449
 
 
450
        *mount_opts = (char *) &data;
 
451
        /* clean up */
 
452
        return 0;
 
453
 
 
454
fail:
 
455
        return retval;
 
456
}