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 <sys/mntent.h>
  39 #include <sys/mnttab.h>
  40 #include <libzfs.h>
  41 #include <libgen.h>
  42 #include <limits.h>
  43 #include <deflt.h>
  44 
  45 #include "funcs.h"
  46 #include "messages.h"
  47 
  48 #define SBUFSZ  256
  49 
  50 #define DEFAULT_USERADD "/etc/default/useradd"
  51 
  52 static int rm_homedir();
  53 static char *get_mnt_special();
  54 
  55 static char cmdbuf[ SBUFSZ ];   /* buffer for system call */
  56 static char dhome[ PATH_MAX + 1 ]; /* buffer for dirname */
  57 static char bhome[ PATH_MAX + 1 ]; /* buffer for basename */
  58 static char pdir[ PATH_MAX + 1 ]; /* parent directory */
  59 static libzfs_handle_t *g_zfs = NULL;
  60 
  61 /*
  62  * Create a home directory and populate with files from skeleton
  63  * directory.
  64  */
  65 int
  66 create_home(char *homedir, char *skeldir, uid_t uid, gid_t gid, int flags)
  67                 /* home directory to create */
  68                 /* skel directory to copy if indicated */
  69                 /* uid of new user */
  70                 /* group id of new user */
  71                 /* miscellaneous flags */
  72 {
  73         struct stat stbuf;
  74         char *dataset;
  75         char *dname, *bname;
  76 
  77         if (g_zfs == NULL)
  78                 g_zfs = libzfs_init();
  79 
  80         (void) strcpy(dhome, homedir);
  81         (void) strcpy(bhome, homedir);
  82         dname = dirname(dhome);
  83         bname = basename(bhome);
  84         (void) strcpy(pdir, dname);
  85 
  86         if ((stat(pdir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode)) {
  87                 errmsg(M_OOPS, "access the parent directory", strerror(errno));
  88                 if (g_zfs) {
  89                         libzfs_fini(g_zfs);
  90                         g_zfs = NULL;
  91                 }
  92                 return (EX_HOMEDIR);
  93         }
  94 
  95         if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
  96             (g_zfs != NULL) && (flags & CHANGE_ZFS_FS) &&
  97             ((dataset = get_mnt_special(pdir, stbuf.st_fstype)) != NULL)) {
  98                 char nm[ZFS_MAXNAMELEN];
  99                 zfs_handle_t *zhp;
 100 
 101                 (void) snprintf(nm, ZFS_MAXNAMELEN, "%s/%s", dataset, bname);
 102 
 103                 if ((zfs_create(g_zfs, nm, ZFS_TYPE_FILESYSTEM, NULL) != 0) ||
 104                     ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) ==
 105                     NULL)) {
 106                         errmsg(M_OOPS, "create the home directory",
 107                             libzfs_error_description(g_zfs));
 108                         libzfs_fini(g_zfs);
 109                         g_zfs = NULL;
 110                         return (EX_HOMEDIR);
 111                 }
 112 
 113                 if (zfs_mount(zhp, NULL, 0) != 0) {
 114                         errmsg(M_OOPS, "mount the home directory",
 115                             libzfs_error_description(g_zfs));
 116                         (void) zfs_destroy(zhp, B_FALSE);
 117                         zfs_close(zhp);
 118                         libzfs_fini(g_zfs);
 119                         g_zfs = NULL;
 120                         return (EX_HOMEDIR);
 121                 }
 122 
 123                 zfs_close(zhp);
 124 
 125                 if (chmod(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
 126                         != 0) {
 127                         errmsg(M_OOPS, "change permissions of home directory",
 128                             strerror(errno));
 129                         libzfs_fini(g_zfs);
 130                         g_zfs = NULL;
 131                         return (EX_HOMEDIR);
 132                 }
 133         } else {
 134                 if (mkdir(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
 135                         != 0) {
 136                         errmsg(M_OOPS, "create the home directory",
 137                             strerror(errno));
 138                         if (g_zfs) {
 139                                 libzfs_fini(g_zfs);
 140                                 g_zfs = NULL;
 141                         }
 142                         return (EX_HOMEDIR);
 143                 }
 144         }
 145 
 146         if (chown(homedir, uid, gid) != 0) {
 147                 errmsg(M_OOPS, "change ownership of home directory",
 148                     strerror(errno));
 149                 if (g_zfs) {
 150                         libzfs_fini(g_zfs);
 151                         g_zfs = NULL;
 152                 }
 153                 return (EX_HOMEDIR);
 154         }
 155 
 156         if (skeldir) {
 157                 /* copy the skel_dir into the home directory */
 158                 (void) sprintf(cmdbuf, "cd %s && find . -print | cpio -pd %s",
 159                         skeldir, homedir);
 160 
 161                 if (system(cmdbuf) != 0) {
 162                         errmsg(M_OOPS, "copy skeleton directory into home "
 163                             "directory", strerror(errno));
 164                         (void) rm_homedir(homedir, flags);
 165                         if (g_zfs) {
 166                                 libzfs_fini(g_zfs);
 167                                 g_zfs = NULL;
 168                         }
 169                         return (EX_HOMEDIR);
 170                 }
 171 
 172                 /* make sure contents in the home dirctory have correct owner */
 173                 (void) sprintf(cmdbuf,
 174                     "cd %s && find . -exec chown %ld:%ld {} \\;",
 175                     homedir, uid, gid);
 176                 if (system(cmdbuf) != 0) {
 177                         errmsg(M_OOPS,
 178                             "change owner and group of files home directory",
 179                             strerror(errno));
 180                         (void) rm_homedir(homedir, flags);
 181                         if (g_zfs) {
 182                                 libzfs_fini(g_zfs);
 183                                 g_zfs = NULL;
 184                         }
 185                         return (EX_HOMEDIR);
 186                 }
 187 
 188         }
 189         if (g_zfs) {
 190                 libzfs_fini(g_zfs);
 191                 g_zfs = NULL;
 192         }
 193         return (EX_SUCCESS);
 194 }
 195 
 196 /* Remove a home directory structure */
 197 int
 198 rm_homedir(char *dir, int flags)
 199 {
 200         struct stat stbuf;
 201         char *nm;
 202 
 203         if ((stat(dir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode))
 204                 return (0);
 205 
 206         if (g_zfs == NULL)
 207                 g_zfs = libzfs_init();
 208 
 209         if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
 210             (flags & CHANGE_ZFS_FS) &&
 211             (g_zfs != NULL) &&
 212             ((nm = get_mnt_special(dir, stbuf.st_fstype)) != NULL)) {
 213                 zfs_handle_t *zhp;
 214 
 215                 if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) != NULL) {
 216                         if ((zfs_unmount(zhp, NULL, 0) == 0) &&
 217                             (zfs_destroy(zhp, B_FALSE) == 0)) {
 218                                 zfs_close(zhp);
 219                                 return (0);
 220                         }
 221 
 222                         (void) zfs_mount(zhp, NULL, 0);
 223                         zfs_close(zhp);
 224                 }
 225         }
 226 
 227         (void) sprintf(cmdbuf, "rm -rf %s", dir);
 228 
 229         return (system(cmdbuf));
 230 }
 231 
 232 int
 233 rm_files(char *homedir, char *user, int flags)
 234 {
 235         if (rm_homedir(homedir, flags) != 0) {
 236                 errmsg(M_RMFILES);
 237                 return (EX_HOMEDIR);
 238         }
 239 
 240         return (EX_SUCCESS);
 241 }
 242 
 243 int
 244 get_default_zfs_flags()
 245 {
 246         int flags = 0;
 247 
 248         if (defopen(DEFAULT_USERADD) == 0) {
 249                 char *defptr;
 250 
 251                 if ((defptr = defread(CHANGE_ZFS_FS_OPT)) != NULL) {
 252                         char let = tolower(*defptr);
 253 
 254                         switch (let) {
 255                                 case 'y':       /* yes */
 256                                         flags |= CHANGE_ZFS_FS;
 257                                 case 'n':       /* no */
 258                                         break;
 259                         }
 260                 }
 261                 (void) defopen((char *)NULL);
 262         }
 263         return (flags);
 264 }
 265 
 266 /* Get the name of a mounted filesytem */
 267 char *
 268 get_mnt_special(char *mountp, char *fstype)
 269 {
 270         struct mnttab entry, search;
 271         char *special = NULL;
 272         FILE *fp;
 273 
 274         search.mnt_special = search.mnt_mntopts = search.mnt_time = NULL;
 275         search.mnt_mountp = mountp;
 276         search.mnt_fstype = fstype;
 277 
 278         if ((fp = fopen(MNTTAB, "r")) != NULL) {
 279                 if (getmntany(fp, &entry, &search) == 0)
 280                         special = entry.mnt_special;
 281 
 282                 (void) fclose(fp);
 283         }
 284 
 285         return (special);
 286 }