1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  *	autod_autofs.c
23  *
24  *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  *	Use is subject to license terms.
26  */
27 
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 #include <sys/mntent.h>
35 #include <sys/mnttab.h>
36 #include <sys/mount.h>
37 #include <sys/utsname.h>
38 #include <sys/tiuser.h>
39 #include <syslog.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <fslib.h>
43 #include <sys/vfs.h>
44 #include <assert.h>
45 #include "automount.h"
46 
47 static int process_opts(char *options, int *directp, int *sawnestp);
48 void netbuf_free(struct netbuf *);
49 
50 int
mount_autofs(struct mapent * me,char * mntpnt,action_list * alp,char * rootp,char * subdir,char * key)51 mount_autofs(
52 	struct mapent *me,
53 	char *mntpnt,
54 	action_list *alp,
55 	char *rootp,
56 	char *subdir,
57 	char *key
58 )
59 {
60 	int mntflags = 0;
61 	struct utsname utsname;
62 	autofs_args *fnip = NULL;
63 	int mount_timeout = AUTOFS_MOUNT_TIMEOUT;
64 	int sawnest, len, error = 0;
65 	char *buf, rel_mntpnt[MAXPATHLEN];
66 
67 	if (trace > 1)
68 		trace_prt(1, "  mount_autofs %s on %s\n",
69 		me->map_fs->mfs_dir, mntpnt);
70 
71 	if (strcmp(mntpnt, "/-") == 0) {
72 		syslog(LOG_ERR, "invalid mountpoint: /-");
73 		return (ENOENT);
74 	}
75 
76 	/*
77 	 * get relative mountpoint
78 	 */
79 	sprintf(rel_mntpnt, ".%s", mntpnt+strlen(rootp));
80 
81 	if (trace > 2)
82 		trace_prt(1, "rel_mntpnt = %s\n", rel_mntpnt);
83 
84 	if (uname(&utsname) < 0) {
85 		error = errno;
86 		syslog(LOG_ERR, "uname %s", strerror(error));
87 		return (error);
88 	}
89 
90 	if ((fnip = (autofs_args *)
91 	    malloc(sizeof (autofs_args))) == NULL) {
92 		goto free_mem;
93 	}
94 	(void) memset((void *) fnip, 0, sizeof (*fnip));
95 
96 	if ((fnip->addr.buf = (char *)malloc(MAXADDRLEN)) == NULL)
97 		goto free_mem;
98 
99 	(void) strcpy(fnip->addr.buf, utsname.nodename);
100 	(void) strcat(fnip->addr.buf, ".autofs");
101 
102 	if ((fnip->opts = malloc(MAX_MNTOPT_STR)) == NULL)
103 		goto free_mem;
104 	strcpy(fnip->opts, me->map_mntopts);
105 
106 	if (process_opts(fnip->opts, &fnip->direct, &sawnest) != 0)
107 		goto free_mem;
108 
109 	fnip->addr.len = strlen(fnip->addr.buf);
110 	fnip->addr.maxlen = fnip->addr.len;
111 
112 	/*
113 	 * get absolute mountpoint
114 	 */
115 	if ((fnip->path = strdup(mntpnt)) == NULL)
116 		goto free_mem;
117 	if ((fnip->map = strdup(me->map_fs->mfs_dir)) == NULL)
118 		goto free_mem;
119 	if ((fnip->subdir = strdup(subdir)) == NULL)
120 		goto free_mem;
121 
122 	/*
123 	 * This timeout is really ignored by autofs, it uses the
124 	 * parent directory's timeout since it's really the one
125 	 * specified/inherited from the original mount by 'automount'
126 	 */
127 	fnip->mount_to = mount_timeout;	/* IGNORED */
128 	fnip->rpc_to = AUTOFS_RPC_TIMEOUT;
129 
130 	if (fnip->direct) {
131 		if (me->map_modified == TRUE || me->map_faked == TRUE) {
132 			if ((fnip->key = strdup(key)) == NULL)
133 				goto free_mem;
134 		} else {
135 			/* wierd case of a direct map pointer in another map */
136 			if ((fnip->key = strdup(fnip->path)) == NULL)
137 				goto free_mem;
138 		}
139 	} else {
140 		fnip->key = NULL;
141 	}
142 
143 	/*
144 	 * Fill out action list.
145 	 */
146 	alp->action.action = AUTOFS_MOUNT_RQ;
147 	if ((alp->action.action_list_entry_u.mounta.spec =
148 	    strdup(me->map_fs->mfs_dir)) == NULL)
149 		goto free_mem;
150 	if ((alp->action.action_list_entry_u.mounta.dir =
151 	    strdup(rel_mntpnt)) == NULL)
152 		goto free_mem;
153 
154 	len = strlen(fnip->opts);
155 	/*
156 	 * Get a buffer for the option string, it holds the map options plus
157 	 * space for "nest" if it isn't already in the option string
158 	 */
159 	if ((buf = (char *)malloc(MAX_MNTOPT_STR)) == NULL)
160 		goto free_mem;
161 	strcpy(buf, fnip->opts);
162 	if (!sawnest) {
163 		if (len + strlen(",nest") + 1 > MAX_MNTOPT_STR)
164 			goto free_mem;
165 		if (len)
166 			(void) strcat(buf, ",");
167 		(void) strcat(buf, "nest");
168 	}
169 	alp->action.action_list_entry_u.mounta.optptr = buf;
170 	alp->action.action_list_entry_u.mounta.optlen = strlen(buf) + 1;
171 	alp->action.action_list_entry_u.mounta.flags =
172 		mntflags | MS_DATA | MS_OPTIONSTR;
173 	if ((alp->action.action_list_entry_u.mounta.fstype =
174 	    strdup(MNTTYPE_AUTOFS)) == NULL)
175 		goto free_mem;
176 	alp->action.action_list_entry_u.mounta.dataptr = (char *)fnip;
177 	alp->action.action_list_entry_u.mounta.datalen = sizeof (*fnip);
178 
179 	return (0);
180 
181 free_mem:
182 	/*
183 	 * We got an error, free the memory we allocated.
184 	 */
185 	syslog(LOG_ERR, "mount_autofs: memory allocation failure");
186 	free_autofs_args(fnip);
187 	alp->action.action_list_entry_u.mounta.dataptr = NULL;
188 	alp->action.action_list_entry_u.mounta.datalen = 0;
189 	free_mounta(&alp->action.action_list_entry_u.mounta);
190 
191 	return (error ? error : ENOMEM);
192 }
193 
194 /*
195  * Set *directp to 1 if "direct" is found, and 0 otherwise
196  * (mounts are indirect by default).  If both "direct" and "indirect" are
197  * found, the last one wins.
198  */
199 static int
process_opts(char * options,int * directp,int * sawnestp)200 process_opts(char *options, int *directp, int *sawnestp)
201 {
202 	char *opt, *opts, *lasts;
203 	char buf[AUTOFS_MAXOPTSLEN];
204 
205 	assert(strlen(options)+1 < AUTOFS_MAXOPTSLEN);
206 
207 	*sawnestp = 0;
208 	strcpy(buf, options);
209 	opts = buf;
210 	options[0] = '\0';
211 	*directp = 0;
212 
213 	while ((opt = strtok_r(opts, ",", &lasts)) != NULL) {
214 		opts = NULL;
215 		while (isspace(*opt)) {
216 			opt++;
217 		}
218 		if (strcmp(opt, "direct") == 0) {
219 			*directp = 1;
220 		} else if (strcmp(opt, "indirect") == 0) {
221 			*directp = 0;
222 		} else if (strcmp(opt, "ignore") != 0) {
223 			if (strcmp(opt, "nest") == 0) {
224 				*sawnestp = 1;
225 			}
226 			if (options[0] != '\0') {
227 				(void) strcat(options, ",");
228 			}
229 			(void) strcat(options, opt);
230 		}
231 	};
232 	return (0);
233 }
234 
235 /*
236  * Free autofs_args structure
237  */
238 void
free_autofs_args(autofs_args * p)239 free_autofs_args(autofs_args *p)
240 {
241 	if (p == NULL)
242 		return;
243 	if (p->addr.buf)
244 		free(p->addr.buf);
245 	if (p->path)
246 		free(p->path);
247 	if (p->opts)
248 		free(p->opts);
249 	if (p->map)
250 		free(p->map);
251 	if (p->subdir)
252 		free(p->subdir);
253 	if (p->key)
254 		free(p->key);
255 	free(p);
256 }
257 
258 /*
259  * free mounta structure. Assumes that m->dataptr has
260  * been freed already
261  */
262 void
free_mounta(struct mounta * m)263 free_mounta(struct mounta *m)
264 {
265 	if (m == NULL)
266 		return;
267 	if (m->spec)
268 		free(m->spec);
269 	if (m->dir)
270 		free(m->dir);
271 	if (m->fstype)
272 		free(m->fstype);
273 	if (m->optptr)
274 		free(m->optptr);
275 	assert(m->dataptr == NULL);
276 	assert(m->datalen == 0);
277 	/*
278 	 * no need to free 'm' since it is part of the
279 	 * action_list_entry structure.
280 	 */
281 }
282