/* * nwmount.c * * Copyright (C) 1995 by Volker Lendecke * * 1/20/96 - Steven N. Hirsch (hirsch@emba.uvm.edu) * * If the ncpfs support is not loaded and we are using kerneld to * autoload modules, then we don't want to do it here. I added * a conditional which leaves out the test and load code. * * Even if we _do_ want ncpmount to load the module, passing a * fully-qualified pathname to insmod causes it to bypass a * path search. This may lead to ncpfs.o not being found on * some systems. */ #include #include #include #include #include #include #include #include #include #include #include /* #include */ /* generates a warning here */ extern pid_t waitpid(pid_t, int *, int); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ncplib.h" static char *progname; static void usage(void); static void help(void); #ifndef HAVE_KERNELD /* Returns 0 if the filesystem is in the kernel after this routine completes */ static int load_ncpfs(void) { FILE *ffs; char s[1024]; char *p, *p1; pid_t pid; int status; /* Check if ncpfs is in the kernel */ ffs = fopen("/proc/filesystems", "r"); if (ffs == NULL) { perror("Error: \"/proc/filesystems\" could not be read:"); return -1; } p = NULL; while (! feof(ffs)) { p1 = fgets(s, sizeof(s), ffs); if (p1) { p = strstr(s, "ncpfs"); if (p) { break; } } } fclose(ffs); if (p) { return 0; } /* system() function without signal handling, from Stevens */ if ((pid = fork()) < 0) { return 1; } else if (pid == 0) { /* child */ execl("/sbin/insmod", "insmod", "ncpfs", NULL); _exit(127); /* execl error */ } else { /* parent */ while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) { status = -1; break; } } } return status; } #endif /* HAVE_KERNELD */ /* Check whether user is allowed to mount on the specified mount point */ static int mount_ok(struct stat *st) { if (!S_ISDIR(st->st_mode)) { errno = ENOTDIR; return -1; } if ( (getuid() != 0) && ( (getuid() != st->st_uid) || ((st->st_mode & S_IRWXU) != S_IRWXU))) { errno = EPERM; return -1; } return 0; } int main(int argc, char *argv[]) { struct ncp_mount_data data; struct stat st; char mount_name[256]; int fd, result; struct sockaddr_ipx addr; int addrlen; int upcase_password; int um; unsigned int flags; char mount_point[MAXPATHLEN]; struct mntent ment; FILE *mtab; char *server = NULL; char *user = NULL; char *password = NULL; struct ncp_conn_spec *spec; uid_t conn_uid = getuid(); struct ncp_conn conn; int opt; progname = argv[0]; memzero(data); memzero(spec); memzero(conn); if (geteuid() != 0) { fprintf(stderr, "%s must be installed suid root\n", progname); exit(1); } data.uid = getuid(); data.gid = getgid(); um = umask(0); umask(um); data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um; data.dir_mode = 0; upcase_password = 1; while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nh")) != EOF) { switch (opt) { case 'C': upcase_password = 0; break; case 'S': if (strlen(optarg) >= sizeof(spec->server)) { fprintf(stderr, "Servername too long:%s\n", optarg); return 1; } server = optarg; break; case 'U': if (strlen(optarg) >= sizeof(spec->user)) { fprintf(stderr, "Username too long: %s\n", optarg); return 1; } user = optarg; break; case 'c': if (isdigit(optarg[0])) { conn_uid = atoi(optarg); } else { struct passwd *pwd = getpwnam(optarg); if (pwd == NULL) { fprintf(stderr, "Unknown user: %s\n", optarg); return 1; } conn_uid = pwd->pw_uid; } break; case 'u': if (isdigit(optarg[0])) { data.uid = atoi(optarg); } else { struct passwd *pwd = getpwnam(optarg); if (pwd == NULL) { fprintf(stderr, "Unknown user: %s\n", optarg); return 1; } data.uid = pwd->pw_uid; } break; case 'g': if (isdigit(optarg[0])) { data.gid = atoi(optarg); } else { struct group *grp = getgrnam(optarg); if (grp == NULL) { fprintf(stderr, "Unknown group: %s\n", optarg); return 1; } data.gid = grp->gr_gid; } break; case 'f': data.file_mode = strtol(optarg, NULL, 8); break; case 'd': data.dir_mode = strtol(optarg, NULL, 8); break; case 'P': if (strlen(optarg) >= sizeof(spec->password)) { printf("password too long\n"); exit(1); } password = optarg; break; case 'n': password = ""; break; case 'h': help(); exit(1); default: usage(); return -1; } } if ((spec = ncp_find_conn_spec(server, user, password, data.uid)) == NULL) { fprintf(stderr, "Could not find valid server/user\n"); exit(1); } if (upcase_password != 0) { str_upper(spec->password); } if (optind != argc-1) { usage(); return -1; } realpath(argv[optind], mount_point); if (stat(mount_point, &st) == -1) { fprintf(stderr, "could not find mount point %s: %s\n", mount_point, strerror(errno)); exit(1); } if (mount_ok(&st) != 0) { fprintf(stderr, "cannot to mount on %s: %s\n", mount_point, strerror(errno)); exit(1); } #ifndef HAVE_KERNELD /* Check if the ncpfs filesystem is in the kernel. If not, attempt * to load the ncpfs module */ if (load_ncpfs() != 0) { fprintf(stderr, "Error: Unable to load ncpfs, exiting...\n"); exit(1); } #endif data.version = NCP_MOUNT_VERSION; data.mounted_uid = conn_uid; if (data.dir_mode == 0) { data.dir_mode = data.file_mode; if ((data.dir_mode & S_IRUSR) != 0) data.dir_mode |= S_IXUSR; if ((data.dir_mode & S_IRGRP) != 0) data.dir_mode |= S_IXGRP; if ((data.dir_mode & S_IROTH) != 0) data.dir_mode |= S_IXOTH; } if (ncp_open(&conn, spec) != 0) { fprintf(stderr, "could not connect to server %s: %s\n", server, strerror(errno)); exit(1); } if (conn.is_connected == CONN_PERMANENT) { fprintf(stderr, "You already have mounted server %s\nas user " "%s\non mount point %s\n", spec->server, spec->user, conn.mount_point); ncp_close(&conn); exit(1); } data.serv_addr = conn.i.addr; ncp_close(&conn); data.ncp_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX); if (data.ncp_fd == -1) { fprintf(stderr, "could not open ncp socket: %s\n", strerror(errno)); exit(1); } data.wdog_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX); if (data.wdog_fd == -1) { fprintf(stderr, "could not open wdog socket: %s\n", strerror(errno)); exit(1); } memzero(addr); addr.sipx_type = NCP_PTYPE; if (bind(data.ncp_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { fprintf(stderr, "\nbind: %s\n", strerror(errno)); fprintf(stderr, "\nMaybe you want to use \n" "ipx_configure --auto_interface=on --auto_primary=on\n" "and try again after waiting a minute.\n\n"); exit(1); } addrlen = sizeof(addr); if (getsockname(data.ncp_fd, (struct sockaddr *)&addr, &addrlen)==-1) { perror("getsockname ncp socket"); close(data.ncp_fd); close(data.wdog_fd); exit(1); } addr.sipx_port = htons(ntohs(addr.sipx_port) + 1); if (bind(data.wdog_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { fprintf(stderr, "bind(wdog_sock, ): %s\n", strerror(errno)); exit(1); } flags = MS_MGC_VAL; data.time_out = 20; data.retry_count = 2; result = mount(NULL, mount_point, "ncpfs", flags, (char *)&data); if (result < 0) { printf("mount failed\n"); exit(1); } if ( (ncp_open_mount(&conn, mount_point) != 0) || (ncp_login_user(&conn, spec->user, spec->password) != 0)) { fprintf(stderr, "%s: login failed\n", strerror(errno)); ncp_close(&conn); umount(mount_point); exit(1); } ncp_close(&conn); strcpy(mount_name, spec->server); strcat(mount_name, "/"); strcat(mount_name, spec->user); ment.mnt_fsname = mount_name; ment.mnt_dir = mount_point; ment.mnt_type = "ncpfs"; ment.mnt_opts = "rw"; ment.mnt_freq = 0; ment.mnt_passno= 0; if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) { fprintf(stderr, "Can't get "MOUNTED"~ lock file"); exit(1); } close(fd); if ((mtab = setmntent(MOUNTED, "a+")) == NULL) { fprintf(stderr, "Can't open " MOUNTED); exit(1); } if (addmntent(mtab, &ment) == 1) { fprintf(stderr, "Can't write mount entry"); exit(1); } if (fchmod(fileno(mtab), 0644) == -1) { fprintf(stderr, "Can't set perms on "MOUNTED); exit(1); } endmntent(mtab); if (unlink(MOUNTED"~") == -1) { fprintf(stderr, "Can't remove "MOUNTED"~"); exit(1); } return 0; } static void usage(void) { printf("usage: %s [options] mount-point\n", progname); printf("Try `%s -h' for more information\n", progname); } static void help(void) { printf("\n"); printf("usage: %s [options] mount-point\n", progname); printf("\n" "-S server Server name to be used\n" "-U username Username sent to server\n" "-u uid uid the mounted files get\n" "-g gid gid the mounted files get\n" "-f mode permission the files get (octal notation)\n" "-d mode permission the dirs get (octal notation)\n" "-c uid uid to identify the connection to mount on\n" " Only makes sense for root\n" "-C Don't convert password to uppercase\n" "-P password Use this password\n" "-n Do not use any password\n" " If neither -P nor -n are given, you are\n" " asked for a password.\n" "-h print this help text\n" "\n"); }