80 #include <sys/sockio.h>
81 #include <net/if.h>
82 #include <rpcsvc/daemon_utils.h>
83 #include <pwd.h>
84 #include <strings.h>
85 #include <tsol/label.h>
86 #include <zone.h>
87 #include <limits.h>
88 #include <libscf.h>
89 #include <libshare.h>
90 #include "smfcfg.h"
91
92 extern void set_nfsv4_ephemeral_mount_to(void);
93
94 extern char *nfs_get_qop_name();
95 extern AUTH *nfs_create_ah();
96 extern enum snego_stat nfs_sec_nego();
97
98 #define MAXHOSTS 512
99
100 #define MNTTYPE_CACHEFS "cachefs"
101
102 /*
103 * host cache states
104 */
105 #define NOHOST 0
106 #define GOODHOST 1
107 #define DEADHOST 2
108
109 #define NFS_ARGS_EXTB_secdata(args, secdata) \
110 { (args).nfs_args_ext = NFS_ARGS_EXTB, \
111 (args).nfs_ext_u.nfs_extB.secdata = secdata; }
112
113 struct cache_entry {
114 struct cache_entry *cache_next;
115 char *cache_host;
116 time_t cache_time;
117 int cache_state;
118 rpcvers_t cache_reqvers;
119 rpcvers_t cache_outvers;
120 char *cache_proto;
121 };
122
123 struct mfs_snego_t {
124 int sec_opt;
125 bool_t snego_done;
126 char *nfs_flavor;
127 seconfig_t nfs_sec;
128 };
129 typedef struct mfs_snego_t mfs_snego_t;
130
131 static struct cache_entry *cache_head = NULL;
132 rwlock_t cache_lock; /* protect the cache chain */
133
134 static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, int, uid_t,
135 action_list *);
136 static int is_nfs_port(char *);
137
138 static void netbuf_free(struct netbuf *);
139 static int get_pathconf(CLIENT *, char *, char *, struct pathcnf **, int);
140 static struct mapfs *enum_servers(struct mapent *, char *);
141 static struct mapfs *get_mysubnet_servers(struct mapfs *);
142 static int subnet_test(int af, struct sioc_addrreq *);
143 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
144 struct netconfig **, char *, ushort_t, struct t_info *);
145
146 static struct netbuf *get_pubfh(char *, rpcvers_t, mfs_snego_t *,
147 struct netconfig **, char *, ushort_t, struct t_info *, caddr_t *,
148 bool_t, char *);
149
150 static int create_homedir(const char *, const char *);
151
152 enum type_of_stuff {
153 SERVER_ADDR = 0,
154 SERVER_PING = 1,
219 * list of support services needed
220 */
221 static char *service_list[] = { STATD, LOCKD, NULL };
222 static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
223
224 static void read_default_nfs(void);
225 static int is_v4_mount(char *);
226 static void start_nfs4cbd(void);
227
228 int
229 mount_nfs(
230 struct mapent *me,
231 char *mntpnt,
232 char *prevhost,
233 int overlay,
234 uid_t uid,
235 action_list **alpp)
236 {
237 struct mapfs *mfs, *mp;
238 int err = -1;
239 int cached;
240 action_list *alp;
241 char *dir;
242
243
244 alp = *alpp;
245
246 read_default_nfs();
247
248 mfs = enum_servers(me, prevhost);
249 if (mfs == NULL)
250 return (ENOENT);
251
252 /*
253 * Try loopback if we have something on localhost; if nothing
254 * works, we will fall back to NFS
255 */
256 if (is_nfs_port(me->map_mntopts)) {
257 for (mp = mfs; mp; mp = mp->mfs_next) {
258 if (self_check(mp->mfs_host)) {
259 err = loopbackmount(mp->mfs_dir,
261 if (err) {
262 mp->mfs_ignore = 1;
263 } else {
264 /*
265 * Free action_list if there
266 * is one as it is not needed.
267 * Make sure to set alpp to null
268 * so caller doesn't try to free it
269 * again.
270 */
271 if (*alpp) {
272 free(*alpp);
273 *alpp = NULL;
274 }
275 break;
276 }
277 }
278 }
279 }
280 if (err) {
281 cached = strcmp(me->map_mounter, MNTTYPE_CACHEFS) == 0;
282 dir = strdup(mfs->mfs_dir);
283 err = nfsmount(mfs, mntpnt, me->map_mntopts,
284 cached, overlay, uid, alp);
285 if (err && trace > 1) {
286 trace_prt(1, " Couldn't mount %s:%s, err=%d\n",
287 mfs->mfs_host ? mfs->mfs_host : "",
288 mfs->mfs_dir ? mfs->mfs_dir : dir, err);
289 }
290 free(dir);
291 }
292 free_mfs(mfs);
293 return (err);
294 }
295
296
297 /*
298 * Using the new ioctl SIOCTONLINK to determine if a host is on the same
299 * subnet. Remove the old network, subnet check.
300 */
301
302 static struct mapfs *
303 get_mysubnet_servers(struct mapfs *mfs_in)
304 {
622 if (m1)
623 free_mfs(m1);
624 m1 = m2;
625 for (m2 = m1; m2; m2 = m2->mfs_next) {
626 p = add_mfs(m2, DIST_OTHER, &mfs_head, &mfs_tail);
627 if (!p)
628 return (NULL);
629 }
630 if (m1)
631 free_mfs(m1);
632
633 done:
634 dump_mfs(mfs_head, " enum_servers: output: ", 1);
635 return (mfs_head);
636 }
637
638 static enum nfsstat
639 nfsmount(
640 struct mapfs *mfs_in,
641 char *mntpnt, char *opts,
642 int cached, int overlay,
643 uid_t uid,
644 action_list *alp)
645 {
646 CLIENT *cl;
647 char remname[MAXPATHLEN], *mnttabtext = NULL;
648 char mopts[MAX_MNTOPT_STR];
649 char netname[MAXNETNAMELEN+1];
650 char *mntopts = NULL;
651 int mnttabcnt = 0;
652 int loglevel;
653 struct mnttab m;
654 struct nfs_args *argp = NULL, *head = NULL, *tail = NULL,
655 *prevhead, *prevtail;
656 int flags;
657 struct fhstatus fhs;
658 struct timeval timeout;
659 enum clnt_stat rpc_stat;
660 enum nfsstat status;
661 struct stat stbuf;
662 struct netconfig *nconf;
698 ushort_t thisport;
699 int got_val;
700 mfs_snego_t mfssnego_init, mfssnego;
701
702 dump_mfs(mfs_in, " nfsmount: input: ", 2);
703 replicated = (mfs_in->mfs_next != NULL);
704 m.mnt_mntopts = opts;
705 if (replicated && hasmntopt(&m, MNTOPT_SOFT)) {
706 if (verbose)
707 syslog(LOG_WARNING,
708 "mount on %s is soft and will not be replicated.", mntpnt);
709 replicated = 0;
710 }
711 if (replicated && !hasmntopt(&m, MNTOPT_RO)) {
712 if (verbose)
713 syslog(LOG_WARNING,
714 "mount on %s is not read-only and will not be replicated.",
715 mntpnt);
716 replicated = 0;
717 }
718 if (replicated && cached) {
719 if (verbose)
720 syslog(LOG_WARNING,
721 "mount on %s is cached and will not be replicated.",
722 mntpnt);
723 replicated = 0;
724 }
725 if (replicated)
726 loglevel = LOG_WARNING;
727 else
728 loglevel = LOG_ERR;
729
730 if (trace > 1) {
731 if (replicated)
732 trace_prt(1, " nfsmount: replicated mount on %s %s:\n",
733 mntpnt, opts);
734 else
735 trace_prt(1, " nfsmount: standard mount on %s %s:\n",
736 mntpnt, opts);
737 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next)
738 trace_prt(1, " %s:%s\n",
739 mfs->mfs_host, mfs->mfs_dir);
740 }
741
742 /*
743 * Make sure mountpoint is safe to mount on
744 */
1163 host = mfs->mfs_host;
1164 dir = mfs->mfs_dir;
1165
1166 /*
1167 * Remember the possible '[a:d:d:r:e:s:s]' as the address to be
1168 * later passed to mount(2) and used in the mnttab line, but
1169 * only use 'a:d:d:r:e:s:s' for communication
1170 */
1171 rhost = strdup(host);
1172 if (rhost == NULL) {
1173 syslog(LOG_ERR, "nfsmount: no memory");
1174 last_error = NFSERR_IO;
1175 goto out;
1176 }
1177 unbracket(&host);
1178
1179 (void) sprintf(remname, "%s:%s", rhost, dir);
1180 if (trace > 4 && replicated)
1181 trace_prt(1, " nfsmount: examining %s\n", remname);
1182
1183 /*
1184 * If it's cached we need to get cachefs to mount it.
1185 */
1186 if (cached) {
1187 char *copts = opts;
1188
1189 /*
1190 * If we started with a URL we need to turn on
1191 * -o public if not on already
1192 */
1193 if (use_pubfh == FALSE &&
1194 (mfs->mfs_flags & MFS_FH_VIA_WEBNFS)) {
1195
1196 copts = malloc(strlen(opts) +
1197 strlen(",public")+1);
1198
1199 if (copts == NULL) {
1200 syslog(LOG_ERR, "nfsmount: no memory");
1201 last_error = NFSERR_IO;
1202 goto out;
1203 }
1204
1205 strcpy(copts, opts);
1206
1207 if (strlen(copts) != 0)
1208 strcat(copts, ",");
1209
1210 strcat(copts, "public");
1211 }
1212
1213 last_error = mount_generic(remname, MNTTYPE_CACHEFS,
1214 copts, mntpnt, overlay);
1215
1216 if (copts != opts)
1217 free(copts);
1218
1219 if (last_error) {
1220 skipentry = 1;
1221 mfs->mfs_ignore = 1;
1222 continue;
1223 }
1224 goto out;
1225 }
1226
1227 if (mfs->mfs_args == NULL) {
1228
1229 /*
1230 * Allocate nfs_args structure
1231 */
1232 argp = (struct nfs_args *)
1233 malloc(sizeof (struct nfs_args));
1234
1235 if (!argp) {
1236 syslog(LOG_ERR, "nfsmount: no memory");
1237 last_error = NFSERR_IO;
1238 goto out;
1239 }
1240
1241 (void) memset(argp, 0, sizeof (*argp));
1242
1243 /*
1244 * RDMA support
1245 * By now Mount argument struct has been allocated,
1246 * either a pub_fh path will be taken or the regular
|
80 #include <sys/sockio.h>
81 #include <net/if.h>
82 #include <rpcsvc/daemon_utils.h>
83 #include <pwd.h>
84 #include <strings.h>
85 #include <tsol/label.h>
86 #include <zone.h>
87 #include <limits.h>
88 #include <libscf.h>
89 #include <libshare.h>
90 #include "smfcfg.h"
91
92 extern void set_nfsv4_ephemeral_mount_to(void);
93
94 extern char *nfs_get_qop_name();
95 extern AUTH *nfs_create_ah();
96 extern enum snego_stat nfs_sec_nego();
97
98 #define MAXHOSTS 512
99
100 /*
101 * host cache states
102 */
103 #define NOHOST 0
104 #define GOODHOST 1
105 #define DEADHOST 2
106
107 #define NFS_ARGS_EXTB_secdata(args, secdata) \
108 { (args).nfs_args_ext = NFS_ARGS_EXTB, \
109 (args).nfs_ext_u.nfs_extB.secdata = secdata; }
110
111 struct cache_entry {
112 struct cache_entry *cache_next;
113 char *cache_host;
114 time_t cache_time;
115 int cache_state;
116 rpcvers_t cache_reqvers;
117 rpcvers_t cache_outvers;
118 char *cache_proto;
119 };
120
121 struct mfs_snego_t {
122 int sec_opt;
123 bool_t snego_done;
124 char *nfs_flavor;
125 seconfig_t nfs_sec;
126 };
127 typedef struct mfs_snego_t mfs_snego_t;
128
129 static struct cache_entry *cache_head = NULL;
130 rwlock_t cache_lock; /* protect the cache chain */
131
132 static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, uid_t,
133 action_list *);
134 static int is_nfs_port(char *);
135
136 static void netbuf_free(struct netbuf *);
137 static int get_pathconf(CLIENT *, char *, char *, struct pathcnf **, int);
138 static struct mapfs *enum_servers(struct mapent *, char *);
139 static struct mapfs *get_mysubnet_servers(struct mapfs *);
140 static int subnet_test(int af, struct sioc_addrreq *);
141 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
142 struct netconfig **, char *, ushort_t, struct t_info *);
143
144 static struct netbuf *get_pubfh(char *, rpcvers_t, mfs_snego_t *,
145 struct netconfig **, char *, ushort_t, struct t_info *, caddr_t *,
146 bool_t, char *);
147
148 static int create_homedir(const char *, const char *);
149
150 enum type_of_stuff {
151 SERVER_ADDR = 0,
152 SERVER_PING = 1,
217 * list of support services needed
218 */
219 static char *service_list[] = { STATD, LOCKD, NULL };
220 static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
221
222 static void read_default_nfs(void);
223 static int is_v4_mount(char *);
224 static void start_nfs4cbd(void);
225
226 int
227 mount_nfs(
228 struct mapent *me,
229 char *mntpnt,
230 char *prevhost,
231 int overlay,
232 uid_t uid,
233 action_list **alpp)
234 {
235 struct mapfs *mfs, *mp;
236 int err = -1;
237 action_list *alp;
238 char *dir;
239
240
241 alp = *alpp;
242
243 read_default_nfs();
244
245 mfs = enum_servers(me, prevhost);
246 if (mfs == NULL)
247 return (ENOENT);
248
249 /*
250 * Try loopback if we have something on localhost; if nothing
251 * works, we will fall back to NFS
252 */
253 if (is_nfs_port(me->map_mntopts)) {
254 for (mp = mfs; mp; mp = mp->mfs_next) {
255 if (self_check(mp->mfs_host)) {
256 err = loopbackmount(mp->mfs_dir,
258 if (err) {
259 mp->mfs_ignore = 1;
260 } else {
261 /*
262 * Free action_list if there
263 * is one as it is not needed.
264 * Make sure to set alpp to null
265 * so caller doesn't try to free it
266 * again.
267 */
268 if (*alpp) {
269 free(*alpp);
270 *alpp = NULL;
271 }
272 break;
273 }
274 }
275 }
276 }
277 if (err) {
278 dir = strdup(mfs->mfs_dir);
279 err = nfsmount(mfs, mntpnt, me->map_mntopts,
280 overlay, uid, alp);
281 if (err && trace > 1) {
282 trace_prt(1, " Couldn't mount %s:%s, err=%d\n",
283 mfs->mfs_host ? mfs->mfs_host : "",
284 mfs->mfs_dir ? mfs->mfs_dir : dir, err);
285 }
286 free(dir);
287 }
288 free_mfs(mfs);
289 return (err);
290 }
291
292
293 /*
294 * Using the new ioctl SIOCTONLINK to determine if a host is on the same
295 * subnet. Remove the old network, subnet check.
296 */
297
298 static struct mapfs *
299 get_mysubnet_servers(struct mapfs *mfs_in)
300 {
618 if (m1)
619 free_mfs(m1);
620 m1 = m2;
621 for (m2 = m1; m2; m2 = m2->mfs_next) {
622 p = add_mfs(m2, DIST_OTHER, &mfs_head, &mfs_tail);
623 if (!p)
624 return (NULL);
625 }
626 if (m1)
627 free_mfs(m1);
628
629 done:
630 dump_mfs(mfs_head, " enum_servers: output: ", 1);
631 return (mfs_head);
632 }
633
634 static enum nfsstat
635 nfsmount(
636 struct mapfs *mfs_in,
637 char *mntpnt, char *opts,
638 int overlay,
639 uid_t uid,
640 action_list *alp)
641 {
642 CLIENT *cl;
643 char remname[MAXPATHLEN], *mnttabtext = NULL;
644 char mopts[MAX_MNTOPT_STR];
645 char netname[MAXNETNAMELEN+1];
646 char *mntopts = NULL;
647 int mnttabcnt = 0;
648 int loglevel;
649 struct mnttab m;
650 struct nfs_args *argp = NULL, *head = NULL, *tail = NULL,
651 *prevhead, *prevtail;
652 int flags;
653 struct fhstatus fhs;
654 struct timeval timeout;
655 enum clnt_stat rpc_stat;
656 enum nfsstat status;
657 struct stat stbuf;
658 struct netconfig *nconf;
694 ushort_t thisport;
695 int got_val;
696 mfs_snego_t mfssnego_init, mfssnego;
697
698 dump_mfs(mfs_in, " nfsmount: input: ", 2);
699 replicated = (mfs_in->mfs_next != NULL);
700 m.mnt_mntopts = opts;
701 if (replicated && hasmntopt(&m, MNTOPT_SOFT)) {
702 if (verbose)
703 syslog(LOG_WARNING,
704 "mount on %s is soft and will not be replicated.", mntpnt);
705 replicated = 0;
706 }
707 if (replicated && !hasmntopt(&m, MNTOPT_RO)) {
708 if (verbose)
709 syslog(LOG_WARNING,
710 "mount on %s is not read-only and will not be replicated.",
711 mntpnt);
712 replicated = 0;
713 }
714 if (replicated)
715 loglevel = LOG_WARNING;
716 else
717 loglevel = LOG_ERR;
718
719 if (trace > 1) {
720 if (replicated)
721 trace_prt(1, " nfsmount: replicated mount on %s %s:\n",
722 mntpnt, opts);
723 else
724 trace_prt(1, " nfsmount: standard mount on %s %s:\n",
725 mntpnt, opts);
726 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next)
727 trace_prt(1, " %s:%s\n",
728 mfs->mfs_host, mfs->mfs_dir);
729 }
730
731 /*
732 * Make sure mountpoint is safe to mount on
733 */
1152 host = mfs->mfs_host;
1153 dir = mfs->mfs_dir;
1154
1155 /*
1156 * Remember the possible '[a:d:d:r:e:s:s]' as the address to be
1157 * later passed to mount(2) and used in the mnttab line, but
1158 * only use 'a:d:d:r:e:s:s' for communication
1159 */
1160 rhost = strdup(host);
1161 if (rhost == NULL) {
1162 syslog(LOG_ERR, "nfsmount: no memory");
1163 last_error = NFSERR_IO;
1164 goto out;
1165 }
1166 unbracket(&host);
1167
1168 (void) sprintf(remname, "%s:%s", rhost, dir);
1169 if (trace > 4 && replicated)
1170 trace_prt(1, " nfsmount: examining %s\n", remname);
1171
1172 if (mfs->mfs_args == NULL) {
1173
1174 /*
1175 * Allocate nfs_args structure
1176 */
1177 argp = (struct nfs_args *)
1178 malloc(sizeof (struct nfs_args));
1179
1180 if (!argp) {
1181 syslog(LOG_ERR, "nfsmount: no memory");
1182 last_error = NFSERR_IO;
1183 goto out;
1184 }
1185
1186 (void) memset(argp, 0, sizeof (*argp));
1187
1188 /*
1189 * RDMA support
1190 * By now Mount argument struct has been allocated,
1191 * either a pub_fh path will be taken or the regular
|