xref: /illumos-gate/usr/src/cmd/oamuser/user/homedir.c (revision e86372a01d2d16a5dd4a64e144ed978ba17fe7dd)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <stdio.h>
35 #include <userdefs.h>
36 #include <errno.h>
37 #include <strings.h>
38 #include <stdlib.h>
39 #include <sys/mntent.h>
40 #include <sys/mnttab.h>
41 #include <libzfs.h>
42 #include <libgen.h>
43 #include <limits.h>
44 #include <deflt.h>
45 
46 #include "funcs.h"
47 #include "messages.h"
48 
49 #define	SBUFSZ	256
50 
51 #define	DEFAULT_USERADD	"/etc/default/useradd"
52 
53 static int rm_homedir();
54 static char *get_mnt_special();
55 
56 static char cmdbuf[ SBUFSZ ];	/* buffer for system call */
57 static char dhome[ PATH_MAX + 1 ]; /* buffer for dirname */
58 static char bhome[ PATH_MAX + 1 ]; /* buffer for basename */
59 static char pdir[ PATH_MAX + 1 ]; /* parent directory */
60 static libzfs_handle_t *g_zfs = NULL;
61 
62 /*
63  * Create a home directory and populate with files from skeleton
64  * directory.
65  */
66 int
67 create_home(char *homedir, char *skeldir, uid_t uid, gid_t gid, int flags)
68 		/* home directory to create */
69 		/* skel directory to copy if indicated */
70 		/* uid of new user */
71 		/* group id of new user */
72 		/* miscellaneous flags */
73 {
74 	struct stat stbuf;
75 	char *dataset;
76 	char *dname, *bname, *rp;
77 	int created_fs = 0;
78 
79 	rp = realpath(homedir, NULL);
80 	if (rp && (strcmp(rp, "/") == 0)) {
81 		return (EX_HOMEDIR);
82 	}
83 
84 	(void) strcpy(dhome, homedir);
85 	(void) strcpy(bhome, homedir);
86 	dname = dirname(dhome);
87 	bname = basename(bhome);
88 	(void) strcpy(pdir, dname);
89 
90 	if ((stat(pdir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode)) {
91 		errmsg(M_OOPS, "access the parent directory", strerror(errno));
92 		return (EX_HOMEDIR);
93 	}
94 
95 	if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
96 	    (flags & MANAGE_ZFS)) {
97 		if (g_zfs == NULL)
98 			g_zfs = libzfs_init();
99 		if (g_zfs == NULL) {
100 			errmsg(M_OOPS, "libzfs_init failure", strerror(errno));
101 			return (EX_HOMEDIR);
102 		}
103 		if ((dataset = get_mnt_special(pdir, stbuf.st_fstype))
104 		    != NULL) {
105 			char nm[ZFS_MAX_DATASET_NAME_LEN];
106 			zfs_handle_t *zhp;
107 
108 			(void) snprintf(nm, sizeof (nm), "%s/%s",
109 			    dataset, bname);
110 
111 			if ((zfs_create(g_zfs, nm, ZFS_TYPE_FILESYSTEM, NULL)
112 				!= 0) ||
113 			    ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) ==
114 			    NULL)) {
115 				errmsg(M_OOPS, "create the home directory",
116 				    libzfs_error_description(g_zfs));
117 				libzfs_fini(g_zfs);
118 				g_zfs = NULL;
119 				return (EX_HOMEDIR);
120 			}
121 
122 			if (zfs_mount(zhp, NULL, 0) != 0) {
123 				errmsg(M_OOPS, "mount the home directory",
124 				    libzfs_error_description(g_zfs));
125 				(void) zfs_destroy(zhp, B_FALSE);
126 				zfs_close(zhp);
127 				libzfs_fini(g_zfs);
128 				g_zfs = NULL;
129 				return (EX_HOMEDIR);
130 			}
131 
132 			zfs_close(zhp);
133 
134 			if (chmod(homedir,
135 				S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
136 				errmsg(M_OOPS,
137 				    "change permissions of home directory",
138 				    strerror(errno));
139 				libzfs_fini(g_zfs);
140 				g_zfs = NULL;
141 				return (EX_HOMEDIR);
142 			}
143 
144 			created_fs = 1;
145 		} else {
146 			errmsg(M_NO_ZFS_MOUNTPOINT, pdir);
147 		}
148 	}
149 
150 	if (!created_fs) {
151 		if (mkdir(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
152 			!= 0) {
153 			errmsg(M_OOPS, "create the home directory",
154 			    strerror(errno));
155 			if (g_zfs != NULL) {
156 				libzfs_fini(g_zfs);
157 				g_zfs = NULL;
158 			}
159 			return (EX_HOMEDIR);
160 		}
161 	}
162 
163 	if (chown(homedir, uid, gid) != 0) {
164 		errmsg(M_OOPS, "change ownership of home directory",
165 		    strerror(errno));
166 		if (g_zfs != NULL) {
167 			libzfs_fini(g_zfs);
168 			g_zfs = NULL;
169 		}
170 		return (EX_HOMEDIR);
171 	}
172 
173 	if (skeldir != NULL) {
174 		/* copy the skel_dir into the home directory */
175 		(void) sprintf(cmdbuf, "cd %s && find . -print | cpio -pd %s",
176 			skeldir, homedir);
177 
178 		if (system(cmdbuf) != 0) {
179 			errmsg(M_OOPS, "copy skeleton directory into home "
180 			    "directory", strerror(errno));
181 			(void) rm_homedir(homedir, flags);
182 			if (g_zfs != NULL) {
183 				libzfs_fini(g_zfs);
184 				g_zfs = NULL;
185 			}
186 			return (EX_HOMEDIR);
187 		}
188 
189 		/* make sure contents in the home dirctory have correct owner */
190 		(void) sprintf(cmdbuf,
191 		    "cd %s && find . -exec chown %ld:%ld {} \\;",
192 		    homedir, uid, gid);
193 		if (system(cmdbuf) != 0) {
194 			errmsg(M_OOPS,
195 			    "change owner and group of files home directory",
196 			    strerror(errno));
197 			(void) rm_homedir(homedir, flags);
198 			if (g_zfs != NULL) {
199 				libzfs_fini(g_zfs);
200 				g_zfs = NULL;
201 			}
202 			return (EX_HOMEDIR);
203 		}
204 
205 	}
206 	if (g_zfs != NULL) {
207 		libzfs_fini(g_zfs);
208 		g_zfs = NULL;
209 	}
210 	return (EX_SUCCESS);
211 }
212 
213 /* Remove a home directory structure */
214 int
215 rm_homedir(char *dir, int flags)
216 {
217 	struct stat stbuf;
218 	char *nm, *rp;
219 
220 	rp = realpath(dir, NULL);
221 	if (rp && (strcmp(rp, "/") == 0)) {
222 		return (0);
223 	}
224 
225 	if ((stat(dir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode))
226 		return (0);
227 
228 	if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
229 	    (flags & MANAGE_ZFS)) {
230 		if (g_zfs == NULL)
231 			g_zfs = libzfs_init();
232 
233 		if (g_zfs == NULL) {
234 			errmsg(M_OOPS, "libzfs_init failure", strerror(errno));
235 			return (EX_HOMEDIR);
236 		}
237 
238 		if ((nm = get_mnt_special(dir, stbuf.st_fstype)) != NULL) {
239 			zfs_handle_t *zhp;
240 
241 			if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM))
242 			    != NULL) {
243 				if ((zfs_unmount(zhp, NULL, 0) == 0) &&
244 				    (zfs_destroy(zhp, B_FALSE) == 0)) {
245 					zfs_close(zhp);
246 					libzfs_fini(g_zfs);
247 					g_zfs = NULL;
248 					return (0);
249 				}
250 
251 				errmsg(M_OOPS, "destroy the home directory",
252 				    libzfs_error_description(g_zfs));
253 
254 				(void) zfs_mount(zhp, NULL, 0);
255 				zfs_close(zhp);
256 
257 				libzfs_fini(g_zfs);
258 				g_zfs = NULL;
259 				return (EX_HOMEDIR);
260 			}
261 		}
262 	}
263 
264 	(void) sprintf(cmdbuf, "rm -rf %s", dir);
265 
266 	if (g_zfs != NULL) {
267 		libzfs_fini(g_zfs);
268 		g_zfs = NULL;
269 	}
270 
271 	return (system(cmdbuf));
272 }
273 
274 int
275 rm_files(char *homedir, char *user, int flags)
276 {
277 	if (rm_homedir(homedir, flags) != 0) {
278 		errmsg(M_RMFILES);
279 		return (EX_HOMEDIR);
280 	}
281 
282 	return (EX_SUCCESS);
283 }
284 
285 int
286 get_default_zfs_flags()
287 {
288 	int flags = 0;
289 
290 	if (defopen(DEFAULT_USERADD) == 0) {
291 		char *defptr;
292 
293 		if ((defptr = defread(MANAGE_ZFS_OPT)) != NULL) {
294 			char let = tolower(*defptr);
295 
296 			switch (let) {
297 				case 'y':	/* yes */
298 					flags |= MANAGE_ZFS;
299 				case 'n':	/* no */
300 					break;
301 			}
302 		}
303 		(void) defopen((char *)NULL);
304 	}
305 	return (flags);
306 }
307 
308 /* Get the name of a mounted filesystem */
309 char *
310 get_mnt_special(char *mountp, char *fstype)
311 {
312 	struct mnttab entry, search;
313 	char *special = NULL;
314 	FILE *fp;
315 
316 	search.mnt_special = search.mnt_mntopts = search.mnt_time = NULL;
317 	search.mnt_mountp = mountp;
318 	search.mnt_fstype = fstype;
319 
320 	if ((fp = fopen(MNTTAB, "r")) != NULL) {
321 		if (getmntany(fp, &entry, &search) == 0)
322 			special = entry.mnt_special;
323 
324 		(void) fclose(fp);
325 	}
326 
327 	return (special);
328 }
329