# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 1990-2002 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.cmd SUBDIRS= lib group user all: TARGET= all install: TARGET= install clean: TARGET= clean clobber: TARGET= clobber lint: TARGET= lint .KEEP_STATE: all install clean clobber lint: $(SUBDIRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2013 RackTop Systems. # # Copyright (c) 2018, Joyent, Inc. include ../../Makefile.cmd GROUPADD= groupadd GROUPDEL= groupdel GROUPMOD= groupmod SBINPROG= $(GROUPADD) $(GROUPDEL) $(GROUPMOD) PROG= $(SBINPROG) ADD_OBJ= groupadd.o add_group.o messages.o DEL_OBJ= groupdel.o del_group.o messages.o MOD_OBJ= groupmod.o mod_group.o messages.o OBJECTS= $(ADD_OBJ) $(DEL_OBJ) $(MOD_OBJ) SRCS= $(OBJECTS:.o=.c) LIBDIR= ../lib LIBUSRGRP= $(LIBDIR)/lib.a LOCAL= ../inc HERE= . LINTFLAGS= -u INSSBINPROG= $(SBINPROG:%=$(ROOTUSRSBIN)/%) CPPFLAGS= -I$(HERE) -I$(LOCAL) $(CPPFLAGS.master) FILEMODE= 0555 # not linted SMATCH=off $(GROUPADD) : OBJS = $(ADD_OBJ) $(GROUPADD) : LDLIBS += $(LIBUSRGRP) -lcmdutils $(GROUPDEL) : OBJS = $(DEL_OBJ) $(GROUPDEL) : LDLIBS += $(LIBUSRGRP) $(GROUPMOD) : OBJS = $(MOD_OBJ) $(GROUPMOD) : LDLIBS += $(LIBUSRGRP) all: $(PROG) $(PROG): $$(OBJS) $(LIBUSRGRP) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) $(GROUPADD): $(ADD_OBJ) $(GROUPMOD): $(MOD_OBJ) $(GROUPDEL): $(DEL_OBJ) install: all $(INSSBINPROG) clean: $(RM) $(OBJECTS) lint: lint_SRCS include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #define GRPTMP "/etc/gtmp" #define GRPBUFSIZ 5120 int add_group(group, gid) char *group; /* name of group to add */ gid_t gid; /* gid of group to add */ { FILE *etcgrp; /* /etc/group file */ FILE *etctmp; /* temp file */ int o_mask; /* old umask value */ int newdone = 0; /* set true when new entry done */ struct stat sb; /* stat buf to copy modes */ char buf[GRPBUFSIZ]; if ((etcgrp = fopen(GROUP, "r")) == NULL) { return (EX_UPDATE); } if (fstat(fileno(etcgrp), &sb) < 0) { /* If we can't get mode, take a default */ sb.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; } o_mask = umask(077); etctmp = fopen(GRPTMP, "w+"); (void) umask(o_mask); if (etctmp == NULL) { fclose(etcgrp); return (EX_UPDATE); } if (fchmod(fileno(etctmp), sb.st_mode) != 0 || fchown(fileno(etctmp), sb.st_uid, sb.st_gid) != 0 || lockf(fileno(etctmp), F_LOCK, 0) != 0) { fclose(etcgrp); fclose(etctmp); unlink(GRPTMP); return (EX_UPDATE); } while (fgets(buf, GRPBUFSIZ, etcgrp) != NULL) { /* Check for NameService reference */ if (!newdone && (buf[0] == '+' || buf[0] == '-')) { (void) fprintf(etctmp, "%s::%u:\n", group, gid); newdone = 1; } fputs(buf, etctmp); } (void) fclose(etcgrp); if (!newdone) { (void) fprintf(etctmp, "%s::%u:\n", group, gid); } if (rename(GRPTMP, GROUP) < 0) { fclose(etctmp); unlink(GRPTMP); return (EX_UPDATE); } (void) fclose(etctmp); return (EX_SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" /* lint error-killers: */ int errmsg(int, int); /* Delete a group from the GROUP file */ int del_group(char *group) { int deleted; FILE *e_fptr, *t_fptr; struct group *grpstruct; char tname[] = "/etc/gtmp.XXXXXX"; int fd; struct stat sbuf; boolean_t haserr; int line = 1; if ((e_fptr = fopen(GROUP, "r")) == NULL) return (EX_UPDATE); if (fstat(fileno(e_fptr), &sbuf) != 0) return (EX_UPDATE); if ((fd = mkstemp(tname)) == -1) return (EX_UPDATE); if ((t_fptr = fdopen(fd, "w")) == NULL) { (void) close(fd); (void) unlink(tname); return (EX_UPDATE); } /* * Get ownership and permissions correct */ if (fchmod(fd, sbuf.st_mode) != 0 || fchown(fd, sbuf.st_uid, sbuf.st_gid) != 0) { (void) fclose(t_fptr); (void) unlink(tname); return (EX_UPDATE); } /* loop thru GROUP looking for the one to delete */ deleted = 0; while ((grpstruct = fgetgrent(e_fptr)) != NULL) { /* check to see if group is one to delete */ if (strcmp(grpstruct->gr_name, group) == 0) deleted = 1; else putgrent(grpstruct, t_fptr); line++; } haserr = !feof(e_fptr); if (haserr) errmsg(M_SYNTAX, line); (void) fclose(e_fptr); if (fclose(t_fptr) != 0 || haserr) { /* GROUP file contains bad entries or write failed. */ (void) unlink(tname); return (EX_UPDATE); } /* If deleted, update GROUP file */ if (deleted) { if (rename(tname, GROUP) != 0) { (void) unlink(tname); return (EX_UPDATE); } return (EX_SUCCESS); } else { (void) unlink(tname); return (EX_NAME_NOT_EXIST); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 RackTop Systems. */ #include #include #include #include #include #include #include #include #include #include #include "messages.h" extern int errmsg(); extern int valid_gid(), add_group(); /* * groupadd [-g gid [-o]] group * * This command adds new groups to the system. Arguments are: * * gid - a gid_t less than MAXUID * group - a string of printable characters excluding colon(:) and less * than MAXGLEN characters long. */ char *cmdname = "groupadd"; int main(int argc, char *argv[]) { int ch; /* return from getopt */ gid_t gid; /* group id */ int oflag = 0; /* flags */ int rc; char *gidstr = NULL; /* gid from command line */ char *grpname; /* group name from command line */ int warning; while ((ch = getopt(argc, argv, "g:o")) != EOF) switch (ch) { case 'g': gidstr = optarg; break; case 'o': oflag++; break; case '?': errmsg(M_AUSAGE); exit(EX_SYNTAX); } if ((oflag && !gidstr) || optind != argc - 1) { errmsg(M_AUSAGE); exit(EX_SYNTAX); } grpname = argv[optind]; switch (valid_gname(grpname, NULL, &warning)) { case INVALID: errmsg(M_GRP_INVALID, grpname); exit(EX_BADARG); /*NOTREACHED*/ case NOTUNIQUE: errmsg(M_GRP_USED, grpname); exit(EX_NAME_EXISTS); /*NOTREACHED*/ } if (warning) warningmsg(warning, grpname); if (gidstr) { /* Given a gid string - validate it */ char *ptr; errno = 0; gid = (gid_t)strtol(gidstr, &ptr, 10); if (*ptr || errno == ERANGE) { errmsg(M_GID_INVALID, gidstr); exit(EX_BADARG); } switch (valid_gid(gid, NULL)) { case RESERVED: errmsg(M_RESERVED, gid); break; case NOTUNIQUE: if (!oflag) { errmsg(M_GRP_USED, gidstr); exit(EX_ID_EXISTS); } break; case INVALID: errmsg(M_GID_INVALID, gidstr); exit(EX_BADARG); case TOOBIG: errmsg(M_TOOBIG, gid); exit(EX_BADARG); } } else { if (findnextgid(DEFRID+1, MAXUID, &gid) != 0) { errmsg(M_GID_INVALID, "default id"); exit(EX_ID_EXISTS); } } if ((rc = add_group(grpname, gid)) != EX_SUCCESS) errmsg(M_UPDATE, "created"); return (rc); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include "messages.h" /* * groupdel group * * This command deletes groups from the system. Arguments are: * * group - a character string group name */ char *cmdname = "groupdel"; extern void errmsg(), exit(); extern int del_group(); int main(int argc, char **argv) { char *group; /* group name from command line */ int retval = 0; if (argc != 2) { errmsg(M_DUSAGE); exit(EX_SYNTAX); } group = argv[1]; switch (retval = del_group(group)) { case EX_UPDATE: errmsg(M_UPDATE, "deleted"); break; case EX_NAME_NOT_EXIST: errmsg(M_NO_GROUP, group); break; } return (retval); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include "messages.h" /* * groupmod -g gid [-o] | -n name group * * This command modifies groups on the system. Arguments are: * * gid - a gid_t less than UID_MAX * name - a string of printable characters excluding colon (:) and less * than MAXGLEN characters long. * group - a string of printable characters excluding colon(:) and less * than MAXGLEN characters long. */ extern int valid_gid(), mod_group(); extern void errmsg(); char *cmdname = "groupmod"; int main(int argc, char *argv[]) { int ch; /* return from getopt */ gid_t gid; /* group id */ int oflag = 0; /* flags */ int valret; /* return from valid_gid() */ char *gidstr = NULL; /* gid from command line */ char *newname = NULL; /* new group name with -n option */ char *grpname; /* group name from command line */ int warning; oflag = 0; /* flags */ while ((ch = getopt(argc, argv, "g:on:")) != EOF) { switch (ch) { case 'g': gidstr = optarg; break; case 'o': oflag++; break; case 'n': newname = optarg; break; case '?': errmsg(M_MUSAGE); exit(EX_SYNTAX); } } if ((oflag && !gidstr) || optind != argc - 1) { errmsg(M_MUSAGE); exit(EX_SYNTAX); } grpname = argv[optind]; if (gidstr) { /* convert gidstr to integer */ char *ptr; errno = 0; gid = (gid_t)strtol(gidstr, &ptr, 10); if (*ptr || errno == ERANGE) { errmsg(M_GID_INVALID, gidstr); exit(EX_BADARG); } switch (valid_gid(gid, NULL)) { case RESERVED: errmsg(M_RESERVED, gid); break; case NOTUNIQUE: if (!oflag) { errmsg(M_GRP_USED, gidstr); exit(EX_ID_EXISTS); } break; case INVALID: errmsg(M_GID_INVALID, gidstr); exit(EX_BADARG); /*NOTREACHED*/ case TOOBIG: errmsg(M_TOOBIG, gid); exit(EX_BADARG); /*NOTREACHED*/ } } else gid = -1; if (newname) { switch (valid_gname(newname, NULL, &warning)) { case INVALID: errmsg(M_GRP_INVALID, newname); exit(EX_BADARG); case NOTUNIQUE: errmsg(M_GRP_USED, newname); exit(EX_NAME_EXISTS); } if (warning) warningmsg(warning, newname); } if ((valret = mod_group(grpname, gid, newname)) != EX_SUCCESS) { if (valret == EX_NAME_NOT_EXIST) errmsg(M_NO_GROUP, grpname); else errmsg(M_UPDATE, "modified"); } return (valret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ char *errmsgs[] = { "WARNING: gid %ld is reserved.\n", "ERROR: invalid syntax.\nusage: groupadd [-g gid [-o]] group\n", "ERROR: invalid syntax.\nusage: groupdel group\n", "ERROR: invalid syntax.\nusage: groupmod -g gid [-o] | -n name group\n", "ERROR: Cannot update system files - group cannot be %s.\n", "ERROR: %s is not a valid group id. Choose another.\n", "ERROR: %s is already in use. Choose another.\n", "ERROR: %s is not a valid group name. Choose another.\n", "ERROR: %s does not exist.\n", "ERROR: Group id %ld is too big. Choose another.\n", "ERROR: Permission denied.\n", "ERROR: Syntax error in group file at line %d.\n", }; int lasterrmsg = sizeof (errmsgs) / sizeof (char *); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* WARNING: gid %d is reserved.\n */ #define M_RESERVED 0 /* ERROR: invalid syntax.\nusage: groupadd [-g gid [-o]] group\n */ #define M_AUSAGE 1 /* ERROR: invalid syntax.\nusage: groupdel group\n */ #define M_DUSAGE 2 /* ERROR: invalid syntax.\nusage: groupmod -g gid [-o] | -n name group\n */ #define M_MUSAGE 3 /* ERROR: Cannot update system files - group cannot be %s.\n */ #define M_UPDATE 4 /* ERROR: %s is not a valid group id. Choose another.\n */ #define M_GID_INVALID 5 /* ERROR: %s is already in use. Choose another.\n */ #define M_GRP_USED 6 /* ERROR: %s is not a valid group name. Choose another.\n */ #define M_GRP_INVALID 7 /* ERROR: %s does not exist.\n */ #define M_NO_GROUP 8 /* ERROR: Group id %d is too big. Choose another.\n */ #define M_TOOBIG 9 /* ERROR: Permission denied.\n */ #define M_PERM_DENIED 10 /* ERROR: Syntax error in group file at line %d.\n */ #define M_SYNTAX 11 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" /* lint error-killers: */ void errmsg(int, int); /* Modify group to new gid and/or new name */ int mod_group(char *group, gid_t gid, char *newgroup) { int modified = 0; int fd; char tname[] = "/etc/gtmp.XXXXXX"; FILE *e_fptr, *t_fptr; struct group *g_ptr; struct stat sbuf; boolean_t haserr; int line = 1; if ((e_fptr = fopen(GROUP, "r")) == NULL) return (EX_UPDATE); if (fstat(fileno(e_fptr), &sbuf) != 0) return (EX_UPDATE); if ((fd = mkstemp(tname)) == -1) return (EX_UPDATE); if ((t_fptr = fdopen(fd, "w")) == NULL) { (void) close(fd); (void) unlink(tname); return (EX_UPDATE); } /* * Get ownership and permissions correct */ if (fchmod(fd, sbuf.st_mode) != 0 || fchown(fd, sbuf.st_uid, sbuf.st_gid) != 0) { (void) fclose(t_fptr); (void) unlink(tname); return (EX_UPDATE); } while ((g_ptr = fgetgrent(e_fptr)) != NULL) { /* check to see if group is one to modify */ if (strcmp(g_ptr->gr_name, group) == 0) { if (newgroup != NULL) g_ptr->gr_name = newgroup; if (gid != -1) g_ptr->gr_gid = gid; modified++; } putgrent(g_ptr, t_fptr); line++; } haserr = !feof(e_fptr); if (haserr) errmsg(M_SYNTAX, line); (void) fclose(e_fptr); if (fclose(t_fptr) != 0 || haserr) { /* GROUP file contains bad entries or write failed. */ (void) unlink(tname); return (EX_UPDATE); } if (modified) { if (rename(tname, GROUP) != 0) { (void) unlink(tname); return (EX_UPDATE); } return (EX_SUCCESS); } else { (void) unlink(tname); return (EX_NAME_NOT_EXIST); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2013 Gary Mills * * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #ifndef _USERS_H #define _USERS_H #include #include #include #define GROUP "/etc/group" /* max number of projects that can be specified when adding a user */ #define NPROJECTS_MAX 1024 /* validation returns */ #define NOTUNIQUE 0 /* not unique */ #define RESERVED 1 /* reserved */ #define UNIQUE 2 /* is unique */ #define TOOBIG 3 /* number too big */ #define INVALID 4 #define LONGNAME 5 /* string too long */ /* * Note: constraints checking for warning (release 2.6), * and these may be enforced in the future releases. */ #define WARN_NAME_TOO_LONG 0x1 #define WARN_BAD_GROUP_NAME 0x2 #define WARN_BAD_LOGNAME_CHAR 0x4 #define WARN_BAD_LOGNAME_FIRST 0x8 #define WARN_NO_LOWERCHAR 0x10 #define WARN_BAD_PROJ_NAME 0x20 #define WARN_LOGGED_IN 0x40 /* Exit codes from passmgmt */ #define PEX_SUCCESS 0 #define PEX_NO_PERM 1 #define PEX_SYNTAX 2 #define PEX_BADARG 3 #define PEX_BADUID 4 #define PEX_HOSED_FILES 5 #define PEX_FAILED 6 #define PEX_MISSING 7 #define PEX_BUSY 8 #define PEX_BADNAME 9 #define REL_PATH(x) (x && *x != '/') /* * interfaces available from the library */ extern int valid_login(char *, struct passwd **, int *); extern int valid_gname(char *, struct group **, int *); extern int valid_group(char *, struct group **, int *); extern int valid_project(char *, struct project *, void *buf, size_t, int *); extern int valid_projname(char *, struct project *, void *buf, size_t, int *); extern void warningmsg(int, char *); extern void putgrent(struct group *, FILE *); /* passmgmt */ #define PASSMGMT "/usr/lib/passmgmt"; #endif /* _USERS_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. LIBRARY= lib.a DATEFILE= ugdates DATEFILESRC= ugdates.dat TXT= $(DATEFILESRC) OBJECTS= putgrent.o \ errmsg.o \ file.o \ vgid.o \ vgname.o \ vgroup.o \ vuid.o \ vlogin.o \ vproj.o \ dates.o \ vexpire.o \ putprojent.o \ vprojid.o \ vprojname.o # include library definitions include ../../Makefile.cmd include ../../../lib/Makefile.lib SRCDIR = . FILEMODE= $(LIBFILEMODE) PRODUCT= $(LIBRARY) $(DATEFILE) # Must retain `lib', since default expands to nothing LLINTLIB= llib-l$(LIBRARY:lib%.a=lib).ln CLEANFILES= $(LLINTLIB) CLOBBERFILES= $(DATEFILE) GENERAL= ../inc CPPFLAGS= -I. -I$(GENERAL) $(CPPFLAGS.master) CERRWARN += -Wno-parentheses CERRWARN += -Wno-type-limits CERRWARN += -Wno-unused-variable # not linted SMATCH=off ARFLAGS= cr AROBJS= `$(LORDER) $(OBJS) | $(TSORT)` LINTFLAGS= -u CLOBBERFILES += $(LIBRARY) .KEEP_STATE: all: $(PRODUCT) $(TXT) $(DATEFILE): $(DATEFILESRC) $(GREP) -v "^#ident" $(DATEFILESRC) > $(DATEFILE) install: all lint: $(LLINTLIB) $(LLINTLIB): $(SRCS) $(LINT.c) -o $(LIBRARY:lib%.a=lib) $(SRCS) > $(LINTOUT) 2>&1 include ../../../lib/Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include extern int putenv(); static int mask_defined = 0; static char *dmaskpath = "DATEMSK=/etc/datemsk"; /* Parse a date string and return time_t value */ time_t p_getdate( string ) char *string; { struct tm *tmptr, *getdate(); time_t rtime; if ( !mask_defined ) { if ( putenv( dmaskpath ) != 0 ) return( (time_t) 0 ); mask_defined = 1; } if( !(tmptr = getdate( string )) ) return( (time_t) 0 ); if ( (rtime = mktime( tmptr )) < 0) return( (time_t) 0); return( rtime ); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /*LINTLIBRARY*/ #include #include #include "users.h" extern char *errmsgs[]; extern int lasterrmsg; extern char *cmdname; /* * synopsis: errmsg(msgid, (arg1, ..., argN)) */ void errmsg(int msgid, ...) { va_list args; va_start(args, msgid); if (msgid >= 0 && msgid < lasterrmsg) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) vfprintf(stderr, errmsgs[ msgid ], args); } va_end(args); } void warningmsg(int what, char *name) { if ((what & WARN_NAME_TOO_LONG) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s name too long.\n", name); } if ((what & WARN_BAD_GROUP_NAME) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s name should be all lower case" " or numeric.\n", name); } if ((what & WARN_BAD_PROJ_NAME) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s name should be all lower case" " or numeric.\n", name); } if ((what & WARN_BAD_LOGNAME_CHAR) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s name should be all alphanumeric," " '-', '_', or '.'\n", name); } if ((what & WARN_BAD_LOGNAME_FIRST) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s name first character" " should be alphabetic.\n", name); } if ((what & WARN_NO_LOWERCHAR) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s name should have at least one " "lower case character.\n", name); } if ((what & WARN_LOGGED_IN) != 0) { (void) fprintf(stderr, "UX: %s: ", cmdname); (void) fprintf(stderr, "%s is currently logged in, some changes" " may not take effect until next login.\n", name); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */ #include #include int check_perm( statbuf, uid, gid, perm ) struct stat statbuf; uid_t uid; gid_t gid; mode_t perm; { int fail = -1; /* assume no permission at onset */ /* Make sure we're dealing with a directory */ if( S_ISDIR( statbuf.st_mode )) { /* * Have a directory, so make sure user has permission * by the various possible methods to this directory. */ if( (statbuf.st_uid == uid) && (statbuf.st_mode & (perm << 6)) == (perm << 6) ) fail = 0; else if( (statbuf.st_gid == gid) && (statbuf.st_mode & (perm << 3)) == (perm << 3) ) fail = 0; else if( (statbuf.st_mode & perm) == perm ) fail = 0; } return( fail ); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include /* * putgrent() function to write a group structure to a file * supports the use of group names that with + or - */ void putgrent(struct group *grpstr, FILE *to) { char **memptr; /* member vector pointer */ if (grpstr->gr_name[0] == '+' || grpstr->gr_name[0] == '-') { /* * if the groupname starts with either a '+' or '-' then * write out what we can as best as we can * we assume that fgetgrent() set gr_gid to 0 so * write a null entry instead of 0 * This should not break /etc/nsswitch.conf for any of * "group: compat", "group: files", "group: nis" * */ (void) fprintf(to, "%s:%s:", grpstr->gr_name, grpstr->gr_passwd != NULL ? grpstr->gr_passwd : ""); if (grpstr->gr_gid == 0) { (void) fprintf(to, ":"); } else { (void) fprintf(to, "%ld:", grpstr->gr_gid); } memptr = grpstr->gr_mem; while (memptr != NULL && *memptr != NULL) { (void) fprintf(to, "%s", *memptr); memptr++; if (memptr != NULL && *memptr != NULL) (void) fprintf(to, ","); } (void) fprintf(to, "\n"); } else { /* * otherwise write out all the fields in the group structure * */ (void) fprintf(to, "%s:%s:%ld:", grpstr->gr_name, grpstr->gr_passwd, grpstr->gr_gid); memptr = grpstr->gr_mem; while (*memptr != NULL) { (void) fprintf(to, "%s", *memptr); memptr++; if (*memptr != NULL) (void) fprintf(to, ","); } (void) fprintf(to, "\n"); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999-2000 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include /* * putprojent() function to write a project structure to a file */ void putprojent(struct project *projstr, FILE *to) { char **memptr; /* member vector pointer */ (void) fprintf(to, "%s:%d:%s:", projstr->pj_name, projstr->pj_projid, projstr->pj_comment); /* * do user names first */ memptr = projstr->pj_users; while (*memptr != NULL) { (void) fprintf(to, "%s", *memptr); memptr++; if (*memptr != NULL) (void) fprintf(to, ","); } (void) fprintf(to, ":"); /* * now do groups */ memptr = projstr->pj_groups; while (*memptr != NULL) { (void) fprintf(to, "%s", *memptr); memptr++; if (*memptr != NULL) (void) fprintf(to, ","); } (void) fprintf(to, ":%s\n", projstr->pj_attr); } #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # %m/%d/%y %I:%M:%S %p %m/%d/%y %H:%M:%S %m/%d/%y %I:%M %p %m/%d/%y %H:%M %m/%d/%y %I %p %m/%d/%y %H %m/%d/%y %m/%d %b %d, %Y %H:%M:%S %p %b %d, %Y %I:%M:%S %B %d, %Y %H:%M:%S %p %B %d, %Y %I:%M:%S %b %d, %Y %H:%M %p %b %d, %Y %I:%M %B %d, %Y %H:%M %p %B %d, %Y %I:%M %b %d, %Y %H %p %b %d, %Y %I %B %d, %Y %H %p %B %d, %Y %I %b %d, %Y %B %d, %Y %b %d %B %d %b %B %m%d9/25/89M%y %m%d9/25/89M%Y %m%d9/25/89M %m%d%H %m%d %m /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright 1997 Sun Microsystems, Inc. All rights reserved. */ /* Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include extern long p_getdate(); /* Validate an expiration date string */ int valid_expire( string, expire ) char *string; time_t *expire; { time_t tmp, now; struct tm *tm; if( !(tmp = (time_t) p_getdate( string ) ) ) return( INVALID ); now = time( (time_t *)0 ); /* Make a time_t for midnight tonight */ tm = localtime( &now ); now -= tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec; now += 24 * 60 * 60; if( tmp < now ) return( INVALID ); if( expire ) *expire = now; return( UNIQUE ); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */ #include #include #include #include #include #include /* MAXUID should be in param.h; if it isn't, try for UID_MAX in limits.h */ #ifndef MAXUID #include #define MAXUID UID_MAX #endif struct group *getgrgid(); /* validate a GID */ int valid_gid( gid, gptr ) gid_t gid; struct group **gptr; { register struct group *t_gptr; if( gid < 0 ) return( INVALID ); if( gid > MAXUID ) return( TOOBIG ); if( t_gptr = getgrgid( gid ) ) { if( gptr ) *gptr = t_gptr; return( NOTUNIQUE ); } if( gid <= DEFGID ) { if( gptr ) *gptr = getgrgid( gid ); return( RESERVED ); } return( UNIQUE ); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1997, by Sun Microsystems, Inc. * All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /*LINTLIBRARY*/ #include #include #include #include #include /* * validate string given as group name. */ int valid_gname(char *group, struct group **gptr, int *warning) { struct group *t_gptr; char *ptr = group; char c; int len = 0; int badchar = 0; *warning = 0; if (!group || !*group) return (INVALID); for (c = *ptr; c != '\0'; ptr++, c = *ptr) { len++; if (!isprint(c) || (c == ':') || (c == '\n')) return (INVALID); if (!(islower(c) || isdigit(c))) badchar++; } /* * XXX constraints causes some operational/compatibility problem. * This has to be revisited in the future as ARC/standards issue. */ if (len > MAXGLEN - 1) *warning = *warning | WARN_NAME_TOO_LONG; if (badchar != 0) *warning = *warning | WARN_BAD_GROUP_NAME; if ((t_gptr = getgrnam(group)) != NULL) { if (gptr) *gptr = t_gptr; return (NOTUNIQUE); } return (UNIQUE); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include #include #include extern int valid_gid(gid_t, struct group **); static int isalldigit(char *); /* * validate a group name or number and return the appropriate * group structure for it. */ int valid_group(char *group, struct group **gptr, int *warning) { int r, warn; long l; char *ptr; struct group *grp; *warning = 0; if (!isalldigit(group)) return (valid_gname(group, gptr, warning)); /* * There are only digits in group name. * strtol() doesn't return negative number here. */ errno = 0; l = strtol(group, &ptr, 10); if ((l == LONG_MAX && errno == ERANGE) || l > MAXUID) { r = TOOBIG; } else { if ((r = valid_gid((gid_t)l, &grp)) == NOTUNIQUE) { /* It is a valid existing gid */ if (gptr != NULL) *gptr = grp; return (NOTUNIQUE); } } /* * It's all digit, but not a valid gid nor an existing gid. * There might be an existing group name of all digits. */ if (valid_gname(group, &grp, &warn) == NOTUNIQUE) { /* It does exist */ *warning = warn; if (gptr != NULL) *gptr = grp; return (NOTUNIQUE); } /* * It isn't either existing gid or group name. We return the * error code from valid_gid() assuming that given string * represents an integer GID. */ return (r); } static int isalldigit(char *str) { while (*str != '\0') { if (!isdigit((unsigned char)*str)) return (0); str++; } return (1); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2013 Gary Mills * * Copyright (c) 1997, by Sun Microsystems, Inc. * All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include /* Defaults file */ #define DEFAULT_USERADD "/etc/default/useradd" /* * validate string given as login name. */ int valid_login(char *login, struct passwd **pptr, int *warning) { struct passwd *t_pptr; char *ptr = login; int bad1char, badc, clower, len; char c; char action; len = 0; clower = 0; badc = 0; bad1char = 0; *warning = 0; if (!login || !*login) return (INVALID); c = *ptr; if (!isalpha(c)) bad1char++; for (; c != '\0'; ptr++, c = *ptr) { len++; if (!isprint(c) || (c == ':') || (c == '\n')) return (INVALID); if (!isalnum(c) && c != '_' && c != '-' && c != '.') badc++; if (islower(c)) clower++; } action = 'w'; if (defopen(DEFAULT_USERADD) == 0) { char *defptr; if ((defptr = defread("EXCEED_TRAD=")) != NULL) { char let = tolower(*defptr); switch (let) { case 'w': /* warning */ case 'e': /* error */ case 's': /* silent */ action = let; break; } } (void) defopen((char *)NULL); } if (len > LOGNAME_MAX) return (LONGNAME); if (len > LOGNAME_MAX_TRAD) { if (action == 'w') *warning = *warning | WARN_NAME_TOO_LONG; else if (action == 'e') return (LONGNAME); } if (clower == 0) *warning = *warning | WARN_NO_LOWERCHAR; if (badc != 0) *warning = *warning | WARN_BAD_LOGNAME_CHAR; if (bad1char != 0) *warning = *warning | WARN_BAD_LOGNAME_FIRST; if ((t_pptr = getpwnam(login)) != NULL) { if (pptr) *pptr = t_pptr; return (NOTUNIQUE); } return (UNIQUE); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include extern int valid_projid(projid_t, struct project *, void *, size_t); /* * validate a project name or number and return the appropriate * project structure for it. */ int valid_project(char *project, struct project *pptr, void *buf, size_t len, int *warning) { projid_t projid; char *ptr; *warning = 0; if (isdigit(*project)) { projid = (projid_t)strtol(project, &ptr, (int)10); if (! *ptr) return (valid_projid(projid, pptr, buf, len)); } for (ptr = project; *ptr != '\0'; ptr++) { if (!isprint(*ptr) || (*ptr == ':') || (*ptr == '\n')) return (INVALID); } /* length checking and other warnings are done in valid_projname() */ return (valid_projname(project, pptr, buf, len, warning)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include /* validate a project id */ int valid_projid(projid_t projid, struct project *pptr, void *buf, size_t len) { struct project pbuf; struct project *t_pptr; if (projid < 0) return (INVALID); if (projid > MAXPROJID) return (TOOBIG); if (t_pptr = getprojbyid(projid, pptr, buf, len)) return (NOTUNIQUE); return (UNIQUE); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include /* * validate string given as project name. */ int valid_projname(char *project, struct project *pptr, void *buf, size_t blen, int *warning) { struct project *t_pptr; char *ptr = project; char c; int len = 0; int badchar = 0; *warning = 0; if (!project || !*project) return (INVALID); for (c = *ptr; c != '\0'; ptr++, c = *ptr) { len++; if (!isprint(c) || (c == ':') || (c == '\n')) return (INVALID); if (!(islower(c) || isdigit(c))) badchar++; } if (len > PROJNAME_MAX) *warning = *warning | WARN_NAME_TOO_LONG; if (badchar != 0) *warning = *warning | WARN_BAD_PROJ_NAME; if ((t_pptr = getprojbyname(project, pptr, buf, blen)) != NULL) return (NOTUNIQUE); return (UNIQUE); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ #include #include #include #include #include #include #ifndef MAXUID #include #define MAXUID UID_MAX #endif struct passwd *getpwuid(); int valid_uid( uid, pptr ) uid_t uid; struct passwd **pptr; { register struct passwd *t_pptr; if( uid <= 0 ) return( INVALID ); if( uid <= DEFRID ) { if( pptr ) *pptr = getpwuid( uid ); return( RESERVED ); } if( uid > MAXUID ) return( TOOBIG ); if( t_pptr = getpwuid( uid ) ) { if( pptr ) *pptr = t_pptr; return( NOTUNIQUE ); } return( UNIQUE ); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 RackTop Systems. # Copyright (c) 2013 Gary Mills # # Copyright (c) 2018, Joyent, Inc. DEFAULTFILES= useradd.dfl include ../../Makefile.cmd USERADD= useradd USERDEL= userdel USERMOD= usermod ROLEADD= roleadd ROLEDEL= roledel ROLEMOD= rolemod SBINPROG= $(USERADD) $(USERDEL) $(USERMOD) # # Removing sysadm: deleted $(SYSADMPROG) from this target. # PROG= $(SBINPROG) PRODUCT= $(PROG) ADD_OBJ= useradd.o homedir.o groups.o call_pass.o \ userdefs.o messages.o val_lgrp.o funcs.o \ val_lprj.o proj.o DEL_OBJ= userdel.o call_pass.o homedir.o isbusy.o \ groups.o messages.o funcs.o proj.o MOD_OBJ= usermod.o movedir.o groups.o homedir.o \ call_pass.o isbusy.o userdefs.o \ messages.o val_lgrp.o funcs.o val_lprj.o \ proj.o OBJECTS= $(ADD_OBJ) $(DEL_OBJ) $(MOD_OBJ) SRCS= $(OBJECTS:.o=.c) LIBDIR= ../lib LIBUSRGRP= $(LIBDIR)/lib.a LIBADM= -ladm LOCAL= ../inc HERE= . LINTFLAGS= -u ROOTSKEL= $(ROOTETC)/skel INSSBINPROG= $(SBINPROG:%=$(ROOTUSRSBIN)/%) INSSKELFILE= $(SKELFILE:%=$(ROOTSKEL)/%) CPPFLAGS= -I$(HERE) -I$(LOCAL) $(CPPFLAGS.master) CERRWARN += -Wno-implicit-function-declaration # not linted SMATCH=off $(INSSBINPROG) : FILEMODE = 0555 $(INSSYSADMPROG): FILEMODE = 0500 $(INSSKELFILE) : FILEMODE = 0644 $(USERADD) : OBJS = $(ADD_OBJ) $(USERADD) : LIBS = $(LIBUSRGRP) $(USERADD) : LDLIBS += -lcmdutils $(USERDEL) : OBJS = $(DEL_OBJ) $(USERDEL) : LIBS = $(LIBUSRGRP) $(USERMOD) : OBJS = $(MOD_OBJ) $(USERMOD) : LIBS = $(LIBUSRGRP) LDLIBS += -lbsm -lnsl -lsecdb -lproject -lzfs -ltsol .PARALLEL: $(OBJECTS) all: $(PRODUCT) $(PROG): $$(OBJS) $$(LIBS) $(LINK.c) $(OBJS) -o $@ $(LIBS) $(LDLIBS) $(POST_PROCESS) $(USERADD): $(ADD_OBJ) $(USERMOD): $(MOD_OBJ) $(USERDEL): $(DEL_OBJ) install: all $(ROOTETCDEFAULTFILES) .WAIT \ $(ROOTSKEL) $(INSSBINPROG) $(INSSKELFILE) $(RM) $(ROOTUSRSBIN)/$(ROLEADD) $(LN) $(ROOTUSRSBIN)/$(USERADD) $(ROOTUSRSBIN)/$(ROLEADD) $(RM) $(ROOTUSRSBIN)/$(ROLEDEL) $(LN) $(ROOTUSRSBIN)/$(USERDEL) $(ROOTUSRSBIN)/$(ROLEDEL) $(RM) $(ROOTUSRSBIN)/$(ROLEMOD) $(LN) $(ROOTUSRSBIN)/$(USERMOD) $(ROOTUSRSBIN)/$(ROLEMOD) clean: $(RM) $(OBJECTS) lint: lint_SRCS include ../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999-2000 by Sun Microsystems, Inc. * All rights reserved. */ #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */ #include #include #include #include #include #include extern int execvp(); int call_passmgmt(nargv) char *nargv[]; { int ret, cpid, wpid; switch (cpid = fork()) { case 0: /* CHILD */ /* * passmgmt should run in same locale as useradd, usermod, * userdel, for locale-sensitive functions like getdate() */ (void) putenv("LC_ALL=C"); if (freopen("/dev/null", "w+", stdout) == NULL || freopen("/dev/null", "w+", stderr) == NULL || execvp(nargv[0], nargv) == -1) exit(EX_FAILURE); break; case -1: /* ERROR */ return (EX_FAILURE); default: /* PARENT */ while ((wpid = wait(&ret)) != cpid) { if (wpid == -1) return (EX_FAILURE); } ret = (ret >> 8) & 0xff; } return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 RackTop Systems. * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "funcs.h" #include "messages.h" #undef GROUP #include "userdefs.h" typedef struct ua_key { const char *key; const char *(*check)(const char *); const char *errstr; char *newvalue; } ua_key_t; static const char role[] = "role name"; static const char prof[] = "profile name"; static const char proj[] = "project name"; static const char priv[] = "privilege set"; static const char auth[] = "authorization"; static const char type[] = "user type"; static const char lock[] = "lock_after_retries value"; static const char roleauth[] = "roleauth"; static const char label[] = "label"; static const char auditflags[] = "audit mask"; static char auditerr[256]; static const char *check_auth(const char *); static const char *check_prof(const char *); static const char *check_role(const char *); static const char *check_proj(const char *); static const char *check_privset(const char *); static const char *check_type(const char *); static const char *check_lock_after_retries(const char *); static const char *check_roleauth(const char *); static const char *check_label(const char *); static const char *check_auditflags(const char *); int nkeys; static ua_key_t keys[] = { /* First entry is always set correctly in main() */ { USERATTR_TYPE_KW, check_type, type }, { USERATTR_AUTHS_KW, check_auth, auth }, { USERATTR_PROFILES_KW, check_prof, prof }, { USERATTR_ROLES_KW, check_role, role }, { USERATTR_DEFAULTPROJ_KW, check_proj, proj }, { USERATTR_LIMPRIV_KW, check_privset, priv }, { USERATTR_DFLTPRIV_KW, check_privset, priv }, { USERATTR_LOCK_AFTER_RETRIES_KW, check_lock_after_retries, lock }, { USERATTR_ROLEAUTH_KW, check_roleauth, roleauth }, { USERATTR_CLEARANCE, check_label, label }, { USERATTR_MINLABEL, check_label, label }, { USERATTR_AUDIT_FLAGS_KW, check_auditflags, auditflags }, }; #define NKEYS (sizeof (keys)/sizeof (ua_key_t)) /* * Change a key, there are three different call sequences: * * key, value - key with option letter, value. * NULL, value - -K key=value option. */ void change_key(const char *key, char *value) { int i; const char *res; if (key == NULL) { key = value; value = strchr(value, '='); /* Bad value */ if (value == NULL) { errmsg(M_INVALID_VALUE); exit(EX_BADARG); } *value++ = '\0'; } for (i = 0; i < NKEYS; i++) { if (strcmp(key, keys[i].key) == 0) { if (keys[i].newvalue != NULL) { /* Can't set a value twice */ errmsg(M_REDEFINED_KEY, key); exit(EX_BADARG); } if (keys[i].check != NULL && (res = keys[i].check(value)) != NULL) { errmsg(M_INVALID, res, keys[i].errstr); exit(EX_BADARG); } keys[i].newvalue = value; nkeys++; return; } } errmsg(M_INVALID_KEY, key); exit(EX_BADARG); } /* * Add the keys to the argument vector. */ void addkey_args(char **argv, int *index) { int i; for (i = 0; i < NKEYS; i++) { const char *key = keys[i].key; char *val = keys[i].newvalue; size_t len; char *arg; if (val == NULL) continue; len = strlen(key) + strlen(val) + 2; arg = malloc(len); (void) snprintf(arg, len, "%s=%s", key, val); argv[(*index)++] = "-K"; argv[(*index)++] = arg; } } /* * Propose a default value for a key and get the actual value back. * If the proposed default value is NULL, return the actual value set. * The key argument is the user_attr key. */ char * getsetdefval(const char *key, char *dflt) { int i; for (i = 0; i < NKEYS; i++) if (strcmp(keys[i].key, key) == 0) { if (keys[i].newvalue != NULL) return (keys[i].newvalue); else return (keys[i].newvalue = dflt); } return (NULL); } char * getusertype(char *cmdname) { static char usertype[MAX_TYPE_LENGTH]; char *cmd; if ((cmd = strrchr(cmdname, '/'))) ++cmd; else cmd = cmdname; /* get user type based on the program name */ if (strncmp(cmd, CMD_PREFIX_USER, strlen(CMD_PREFIX_USER)) == 0) strcpy(usertype, USERATTR_TYPE_NORMAL_KW); else strcpy(usertype, USERATTR_TYPE_NONADMIN_KW); return (usertype); } int is_role(char *usertype) { if (strcmp(usertype, USERATTR_TYPE_NONADMIN_KW) == 0) return (1); /* not a role */ return (0); } /* * Verifies the provided list of authorizations are all valid. * * Returns NULL if all authorization names are valid. * Otherwise, returns the invalid authorization name * */ static const char * check_auth(const char *auths) { char *authname; authattr_t *result; char *tmp; struct passwd *pw; int have_grant = 0; tmp = strdup(auths); if (tmp == NULL) { errmsg(M_NOSPACE); exit(EX_FAILURE); } authname = strtok(tmp, AUTH_SEP); pw = getpwuid(getuid()); if (pw == NULL) { return (authname); } while (authname != NULL) { char *suffix; char *authtoks; /* Check if user has been granted this authorization */ if (!chkauthattr(authname, pw->pw_name)) return (authname); /* Remove named object after slash */ if ((suffix = index(authname, KV_OBJECTCHAR)) != NULL) *suffix = '\0'; /* Find the suffix */ if ((suffix = rindex(authname, '.')) == NULL) return (authname); /* Check for existence in auth_attr */ suffix++; if (strcmp(suffix, KV_WILDCARD)) { /* Not a wildcard */ result = getauthnam(authname); if (result == NULL) { /* can't find the auth */ free_authattr(result); return (authname); } free_authattr(result); } /* Check if user can delegate this authorization */ if (strcmp(suffix, "grant")) { /* Not a grant option */ authtoks = malloc(strlen(authname) + sizeof ("grant")); strcpy(authtoks, authname); have_grant = 0; while ((suffix = rindex(authtoks, '.')) && !have_grant) { strcpy(suffix, ".grant"); if (chkauthattr(authtoks, pw->pw_name)) have_grant = 1; else *suffix = '\0'; } if (!have_grant) return (authname); } authname = strtok(NULL, AUTH_SEP); } free(tmp); return (NULL); } /* * Verifies the provided list of profile names are valid. * * Returns NULL if all profile names are valid. * Otherwise, returns the invalid profile name * */ static const char * check_prof(const char *profs) { char *profname; profattr_t *result; char *tmp; tmp = strdup(profs); if (tmp == NULL) { errmsg(M_NOSPACE); exit(EX_FAILURE); } profname = strtok(tmp, PROF_SEP); while (profname != NULL) { result = getprofnam(profname); if (result == NULL) { /* can't find the profile */ return (profname); } free_profattr(result); profname = strtok(NULL, PROF_SEP); } free(tmp); return (NULL); } /* * Verifies the provided list of role names are valid. * * Returns NULL if all role names are valid. * Otherwise, returns the invalid role name * */ static const char * check_role(const char *roles) { char *rolename; userattr_t *result; char *utype; char *tmp; tmp = strdup(roles); if (tmp == NULL) { errmsg(M_NOSPACE); exit(EX_FAILURE); } rolename = strtok(tmp, ROLE_SEP); while (rolename != NULL) { result = getusernam(rolename); if (result == NULL) { /* can't find the rolename */ return (rolename); } /* Now, make sure it is a role */ utype = kva_match(result->attr, USERATTR_TYPE_KW); if (utype == NULL) { /* no user type defined. not a role */ free_userattr(result); return (rolename); } if (strcmp(utype, USERATTR_TYPE_NONADMIN_KW) != 0) { free_userattr(result); return (rolename); } free_userattr(result); rolename = strtok(NULL, ROLE_SEP); } free(tmp); return (NULL); } static const char * check_proj(const char *proj) { if (getprojidbyname(proj) < 0) { return (proj); } else { return (NULL); } } static const char * check_privset(const char *pset) { priv_set_t *tmp; const char *res; tmp = priv_str_to_set(pset, ",", &res); if (tmp != NULL) { res = NULL; priv_freeset(tmp); } else if (res == NULL) res = strerror(errno); return (res); } static const char * check_type(const char *type) { if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) != 0 && strcmp(type, USERATTR_TYPE_NORMAL_KW) != 0) return (type); return (NULL); } static const char * check_lock_after_retries(const char *keyval) { if (keyval != NULL) { if (strcasecmp(keyval, USERATTR_LOCK_NO) != 0 && strcasecmp(keyval, USERATTR_LOCK_YES) != 0 && *keyval != '\0') { return (keyval); } } return (NULL); } static const char * check_roleauth(const char *keyval) { if (keyval != NULL) { if (strcasecmp(keyval, USERATTR_ROLEAUTH_USER) != 0 && strcasecmp(keyval, USERATTR_ROLEAUTH_ROLE) != 0 && *keyval != '\0') { return (keyval); } } return (NULL); } static const char * check_label(const char *labelstr) { int err; m_label_t *lbl = NULL; if (!is_system_labeled()) return (NULL); err = str_to_label(labelstr, &lbl, MAC_LABEL, L_NO_CORRECTION, NULL); m_label_free(lbl); if (err == -1) return (labelstr); return (NULL); } static const char * check_auditflags(const char *auditflags) { au_mask_t mask; char *flags; char *last = NULL; char *err = "NULL"; /* if deleting audit_flags */ if (*auditflags == '\0') { return (NULL); } if ((flags = _strdup_null((char *)auditflags)) == NULL) { errmsg(M_NOSPACE); exit(EX_FAILURE); } if (!__chkflags(_strtok_escape(flags, KV_AUDIT_DELIMIT, &last), &mask, B_FALSE, &err)) { (void) snprintf(auditerr, sizeof (auditerr), "always mask \"%s\"", err); free(flags); return (auditerr); } if (!__chkflags(_strtok_escape(NULL, KV_AUDIT_DELIMIT, &last), &mask, B_FALSE, &err)) { (void) snprintf(auditerr, sizeof (auditerr), "never mask \"%s\"", err); free(flags); return (auditerr); } if (last != NULL) { (void) snprintf(auditerr, sizeof (auditerr), "\"%s\"", auditflags); free(flags); return (auditerr); } free(flags); return (NULL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1999,2002-2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _FUNCS_H #define _FUNCS_H #ifdef __cplusplus extern "C" { #endif #define CMD_PREFIX_USER "user" #define AUTH_SEP "," #define PROF_SEP "," #define ROLE_SEP "," #define MAX_TYPE_LENGTH 64 char *getusertype(char *cmdname); int is_role(char *usertype); void change_key(const char *, char *); void addkey_args(char **, int *); char *getsetdefval(const char *, char *); extern int nkeys; /* create_home() or rm_files() flags */ #define MANAGE_ZFS_OPT "MANAGE_ZFS=" #define MANAGE_ZFS 1 #ifdef __cplusplus } #endif #endif /* _FUNCS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" #define MYBUFSIZE (LINE_MAX) /* Corresponds to MYBUFSIZE in grpck.c, BUFCONST in nss_dbdefs.c */ int edit_group(char *login, char *new_login, gid_t gids[], int overwrite) { char **memptr; char t_name[] = "/etc/gtmp.XXXXXX"; int fd; FILE *e_fptr, *t_fptr; struct group *g_ptr; /* group structure from fgetgrent */ int i; int modified = 0; struct stat sbuf; int bufsize, g_length, sav_errno; long g_curr = 0L; char *g_string, *new_g_string, *gstr_off; if ((e_fptr = fopen(GROUP, "r")) == NULL) return (EX_UPDATE); if (fstat(fileno(e_fptr), &sbuf) != 0) { (void) fclose(e_fptr); return (EX_UPDATE); } if ((fd = mkstemp(t_name)) == -1) { (void) fclose(e_fptr); return (EX_UPDATE); } if ((t_fptr = fdopen(fd, "w")) == NULL) { (void) close(fd); (void) unlink(t_name); (void) fclose(e_fptr); return (EX_UPDATE); } /* * Get ownership and permissions correct */ if (fchmod(fd, sbuf.st_mode) != 0 || fchown(fd, sbuf.st_uid, sbuf.st_gid) != 0) { (void) fclose(t_fptr); (void) fclose(e_fptr); (void) unlink(t_name); return (EX_UPDATE); } g_curr = ftell(e_fptr); /* Make TMP file look like we want GROUP file to look */ bufsize = MYBUFSIZE; if ((g_string = malloc(bufsize)) == NULL) { (void) fclose(t_fptr); (void) fclose(e_fptr); (void) unlink(t_name); return (EX_UPDATE); } /* * bufsize contains the size of the currently allocated buffer * buffer size, which is initially MYBUFSIZE but when a line * greater than MYBUFSIZE is encountered then bufsize gets increased * by MYBUFSIZE. * g_string always points to the beginning of the buffer (even after * realloc()). * gstr_off = g_string + MYBUFSIZE * (n), where n >= 0. */ while (!feof(e_fptr) && !ferror(e_fptr)) { g_length = 0; gstr_off = g_string; while (fgets(gstr_off, (bufsize - g_length), e_fptr) != NULL) { g_length += strlen(gstr_off); if (g_string[g_length - 1] == '\n' || feof(e_fptr)) break; new_g_string = realloc(g_string, (bufsize + MYBUFSIZE)); if (new_g_string == NULL) { free(g_string); (void) fclose(t_fptr); (void) fclose(e_fptr); (void) unlink(t_name); return (EX_UPDATE); } bufsize += MYBUFSIZE; g_string = new_g_string; gstr_off = g_string + g_length; } if (g_length == 0) { continue; } /* While there is another group string */ (void) fseek(e_fptr, g_curr, SEEK_SET); errno = 0; g_ptr = fgetgrent(e_fptr); sav_errno = errno; g_curr = ftell(e_fptr); if (g_ptr == NULL) { /* tried to parse a group string over MYBUFSIZ char */ if (sav_errno == ERANGE) errmsg(M_GROUP_ENTRY_OVF); else errmsg(M_READ_ERROR); modified = 0; /* bad group file: cannot rebuild */ break; } /* first delete the login from the group, if it's there */ if (overwrite || !gids) { if (g_ptr->gr_mem != NULL) { for (memptr = g_ptr->gr_mem; *memptr; memptr++) { if (strcmp(*memptr, login) == 0) { /* Delete this one */ char **from = memptr + 1; g_length -= (strlen(*memptr)+1); do { *(from - 1) = *from; } while (*from++); modified++; break; } } } } /* now check to see if group is one to add to */ if (gids) { for (i = 0; gids[i] != -1; i++) { if (g_ptr->gr_gid == gids[i]) { /* Find end */ for (memptr = g_ptr->gr_mem; *memptr; memptr++) ; g_length += strlen(new_login ? new_login : login)+1; *memptr++ = new_login ? new_login : login; *memptr = NULL; modified++; } } } putgrent(g_ptr, t_fptr); } free(g_string); (void) fclose(e_fptr); if (fclose(t_fptr) != 0) { (void) unlink(t_name); return (EX_UPDATE); } /* Now, update GROUP file, if it was modified */ if (modified) { if (rename(t_name, GROUP) != 0) { (void) unlink(t_name); return (EX_UPDATE); } return (EX_SUCCESS); } else { (void) unlink(t_name); return (EX_SUCCESS); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "funcs.h" #include "messages.h" #define SBUFSZ 256 #define DEFAULT_USERADD "/etc/default/useradd" static int rm_homedir(); static char *get_mnt_special(); static char cmdbuf[ SBUFSZ ]; /* buffer for system call */ static char dhome[ PATH_MAX + 1 ]; /* buffer for dirname */ static char bhome[ PATH_MAX + 1 ]; /* buffer for basename */ static char pdir[ PATH_MAX + 1 ]; /* parent directory */ static libzfs_handle_t *g_zfs = NULL; /* * Create a home directory and populate with files from skeleton * directory. */ int create_home(char *homedir, char *skeldir, uid_t uid, gid_t gid, int flags) /* home directory to create */ /* skel directory to copy if indicated */ /* uid of new user */ /* group id of new user */ /* miscellaneous flags */ { struct stat stbuf; char *dataset; char *dname, *bname, *rp; int created_fs = 0; rp = realpath(homedir, NULL); if (rp && (strcmp(rp, "/") == 0)) { return (EX_HOMEDIR); } (void) strcpy(dhome, homedir); (void) strcpy(bhome, homedir); dname = dirname(dhome); bname = basename(bhome); (void) strcpy(pdir, dname); if ((stat(pdir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode)) { errmsg(M_OOPS, "access the parent directory", strerror(errno)); return (EX_HOMEDIR); } if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) && (flags & MANAGE_ZFS)) { if (g_zfs == NULL) g_zfs = libzfs_init(); if (g_zfs == NULL) { errmsg(M_OOPS, "libzfs_init failure", strerror(errno)); return (EX_HOMEDIR); } if ((dataset = get_mnt_special(pdir, stbuf.st_fstype)) != NULL) { char nm[ZFS_MAX_DATASET_NAME_LEN]; zfs_handle_t *zhp; (void) snprintf(nm, sizeof (nm), "%s/%s", dataset, bname); if ((zfs_create(g_zfs, nm, ZFS_TYPE_FILESYSTEM, NULL) != 0) || ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)) { errmsg(M_OOPS, "create the home directory", libzfs_error_description(g_zfs)); libzfs_fini(g_zfs); g_zfs = NULL; return (EX_HOMEDIR); } if (zfs_mount(zhp, NULL, 0) != 0) { errmsg(M_OOPS, "mount the home directory", libzfs_error_description(g_zfs)); (void) zfs_destroy(zhp, B_FALSE); zfs_close(zhp); libzfs_fini(g_zfs); g_zfs = NULL; return (EX_HOMEDIR); } zfs_close(zhp); if (chmod(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) { errmsg(M_OOPS, "change permissions of home directory", strerror(errno)); libzfs_fini(g_zfs); g_zfs = NULL; return (EX_HOMEDIR); } created_fs = 1; } else { errmsg(M_NO_ZFS_MOUNTPOINT, pdir); } } if (!created_fs) { if (mkdir(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) { errmsg(M_OOPS, "create the home directory", strerror(errno)); if (g_zfs != NULL) { libzfs_fini(g_zfs); g_zfs = NULL; } return (EX_HOMEDIR); } } if (chown(homedir, uid, gid) != 0) { errmsg(M_OOPS, "change ownership of home directory", strerror(errno)); if (g_zfs != NULL) { libzfs_fini(g_zfs); g_zfs = NULL; } return (EX_HOMEDIR); } if (skeldir != NULL) { /* copy the skel_dir into the home directory */ (void) sprintf(cmdbuf, "cd %s && find . -print | cpio -pd %s", skeldir, homedir); if (system(cmdbuf) != 0) { errmsg(M_OOPS, "copy skeleton directory into home " "directory", strerror(errno)); (void) rm_homedir(homedir, flags); if (g_zfs != NULL) { libzfs_fini(g_zfs); g_zfs = NULL; } return (EX_HOMEDIR); } /* make sure contents in the home dirctory have correct owner */ (void) sprintf(cmdbuf, "cd %s && find . -exec chown %ld:%ld {} \\;", homedir, uid, gid); if (system(cmdbuf) != 0) { errmsg(M_OOPS, "change owner and group of files home directory", strerror(errno)); (void) rm_homedir(homedir, flags); if (g_zfs != NULL) { libzfs_fini(g_zfs); g_zfs = NULL; } return (EX_HOMEDIR); } } if (g_zfs != NULL) { libzfs_fini(g_zfs); g_zfs = NULL; } return (EX_SUCCESS); } /* Remove a home directory structure */ int rm_homedir(char *dir, int flags) { struct stat stbuf; char *nm, *rp; rp = realpath(dir, NULL); if (rp && (strcmp(rp, "/") == 0)) { return (0); } if ((stat(dir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode)) return (0); if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) && (flags & MANAGE_ZFS)) { if (g_zfs == NULL) g_zfs = libzfs_init(); if (g_zfs == NULL) { errmsg(M_OOPS, "libzfs_init failure", strerror(errno)); return (EX_HOMEDIR); } if ((nm = get_mnt_special(dir, stbuf.st_fstype)) != NULL) { zfs_handle_t *zhp; if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) != NULL) { if ((zfs_unmount(zhp, NULL, 0) == 0) && (zfs_destroy(zhp, B_FALSE) == 0)) { zfs_close(zhp); libzfs_fini(g_zfs); g_zfs = NULL; return (0); } errmsg(M_OOPS, "destroy the home directory", libzfs_error_description(g_zfs)); (void) zfs_mount(zhp, NULL, 0); zfs_close(zhp); libzfs_fini(g_zfs); g_zfs = NULL; return (EX_HOMEDIR); } } } (void) sprintf(cmdbuf, "rm -rf %s", dir); if (g_zfs != NULL) { libzfs_fini(g_zfs); g_zfs = NULL; } return (system(cmdbuf)); } int rm_files(char *homedir, char *user, int flags) { if (rm_homedir(homedir, flags) != 0) { errmsg(M_RMFILES); return (EX_HOMEDIR); } return (EX_SUCCESS); } int get_default_zfs_flags() { int flags = 0; if (defopen(DEFAULT_USERADD) == 0) { char *defptr; if ((defptr = defread(MANAGE_ZFS_OPT)) != NULL) { char let = tolower(*defptr); switch (let) { case 'y': /* yes */ flags |= MANAGE_ZFS; case 'n': /* no */ break; } } (void) defopen((char *)NULL); } return (flags); } /* Get the name of a mounted filesystem */ char * get_mnt_special(char *mountp, char *fstype) { struct mnttab entry, search; char *special = NULL; FILE *fp; search.mnt_special = search.mnt_mntopts = search.mnt_time = NULL; search.mnt_mountp = mountp; search.mnt_fstype = fstype; if ((fp = fopen(MNTTAB, "r")) != NULL) { if (getmntany(fp, &entry, &search) == 0) special = entry.mnt_special; (void) fclose(fp); } return (special); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1998 by Sun Microsystems, Inc. * All rights reserved. */ #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */ #include #include #include #include #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif int isbusy(char *); /* Is this login being used */ int isbusy(char *login) { struct utmpx *utxptr; setutxent(); while ((utxptr = getutxent()) != NULL) /* * If login is in the utmp file, and that process * isn't dead, then it "is_busy()" */ if ((strncmp(login, utxptr->ut_user, sizeof (utxptr->ut_user)) == 0) && \ utxptr->ut_type != DEAD_PROCESS) return (TRUE); return (FALSE); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 Gary Mills * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ char *errmsgs[] = { "WARNING: uid %ld is reserved.\n", "WARNING: more than NGROUPS_MAX(%d) groups specified.\n", "ERROR: invalid syntax.\n" "usage: useradd [-u uid [-o] | -g group | -G group[[,group]...] |" "-d dir | -b base_dir |\n" "\t\t-s shell | -c comment | -m [-z|Z] [-k skel_dir] |" "-f inactive |\n" "\t\t-e expire | -A authorization [, authorization ...] |\n" "\t\t-P profile [, profile ...] | -R role [, role ...] |\n" "\t\t-K key=value | -p project [, project ...]] login\n" "\tuseradd -D [-g group | -b base_dir | -f inactive | -e expire\n" "\t\t-A authorization [, authorization ...] |\n" "\t\t-P profile [, profile ...] | -R role [, role ...] |\n" "\t\t-K key=value ... -p project] | [-s shell] | [-k skel_dir]\n", "ERROR: Invalid syntax.\nusage: userdel [-r] login\n", "ERROR: Invalid syntax.\n" "usage: usermod -u uid [-o] | -g group | -G group[[,group]...] |\n" "\t\t-d dir [-m [-z|Z]] | -s shell | -c comment |\n" "\t\t-l new_logname | -f inactive | -e expire |\n" "\t\t-A authorization [, authorization ...] | -K key=value ... |\n" "\t\t-P profile [, profile ...] | -R role [, role ...] login\n", "ERROR: Unexpected failure. Defaults unchanged.\n", "ERROR: Unable to remove files from home directory.\n", "ERROR: Unable to remove home directory.\n", "ERROR: Cannot update system files - login cannot be %s.\n", "ERROR: uid %ld is already in use. Choose another.\n", "ERROR: %s is already in use. Choose another.\n", "ERROR: %s does not exist.\n", "ERROR: %s is not a valid %s. Choose another.\n", "ERROR: %s is in use. Cannot %s it.\n", "WARNING: %s has no permissions to use %s.\n", "ERROR: There is not sufficient space to move %s home directory to %s" "\n", "ERROR: %s %ld is too big. Choose another.\n", "ERROR: group %s does not exist. Choose another.\n", "ERROR: Unable to %s: %s.\n", "ERROR: %s is not a full path name. Choose another.\n", "ERROR: %s is the primary group name. Choose another.\n", "ERROR: Inconsistent password files. See pwconv(8).\n", "ERROR: %s is not a local user.\n", "ERROR: Permission denied.\n", "WARNING: Group entry exceeds 2048 char: /etc/group entry truncated.\n", "ERROR: invalid syntax.\n" "usage: roleadd [-u uid [-o] | -g group | -G group[[,group]...] |" "-d dir |\n" "\t\t-s shell | -c comment | -m [-k skel_dir] | -f inactive |\n" "\t\t-e expire | -A authorization [, authorization ...] |\n" "\t\t-P profile [, profile ...] | -K key=value ] login\n" "\troleadd -D [-g group | -b base_dir | -f inactive | -e expire\n" "\t\t-A authorization [, authorization ...] |\n" "\t\t-P profile [, profile ...]]\n", "ERROR: Invalid syntax.\nusage: roledel [-r] login\n", "ERROR: Invalid syntax.\n" "usage: rolemod -u uid [-o] | -g group | -G group[[,group]...] |\n" "\t\t-d dir [-m] | -s shell | -c comment |\n" "\t\t-l new_logname | -f inactive | -e expire |\n" "\t\t-A authorization [, authorization ...] | -K key=value |\n" "\t\t-P profile [, profile ...] login\n", "ERROR: project %s does not exist. Choose another.\n", "WARNING: more than NPROJECTS_MAX(%d) projects specified.\n", "WARNING: Project entry exceeds %d char: /etc/project entry truncated." "\n", "ERROR: Invalid key.\n", "ERROR: Missing value specification.\n", "ERROR: Multiple definitions of key ``%s''.\n", "ERROR: Roles must be modified with ``rolemod''.\n", "ERROR: Users must be modified with ``usermod''.\n", "WARNING: gid %ld is reserved.\n", "ERROR: Failed to read /etc/group file due to invalid entry or" " read error.\n", "ERROR: %s is too long. Choose another.\n", "WARNING: Avoided creating ZFS filesystem as parent directory %s is not" " a ZFS mount point.\n", }; int lasterrmsg = sizeof (errmsgs) / sizeof (char *); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 Gary Mills * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _MESSAGES_H #define _MESSAGES_H extern void errmsg(int, ...); /* WARNING: uid %d is reserved. */ #define M_RESERVED 0 /* WARNING: more than NGROUPS_MAX(%d) groups specified. */ #define M_MAXGROUPS 1 /* ERROR: invalid syntax.\nusage: useradd ... */ #define M_AUSAGE 2 /* ERROR: Invalid syntax.\nusage: userdel [-r] login\n" */ #define M_DUSAGE 3 /* ERROR: Invalid syntax.\nusage: usermod ... */ #define M_MUSAGE 4 /* ERROR: Unexpected failure. Defaults unchanged. */ #define M_FAILED 5 /* ERROR: Unable to remove files from home directory. */ #define M_RMFILES 6 /* ERROR: Unable to remove home directory. */ #define M_RMHOME 7 /* ERROR: Cannot update system files - login cannot be %s. */ #define M_UPDATE 8 /* ERROR: uid %d is already in use. Choose another. */ #define M_UID_USED 9 /* ERROR: %s is already in use. Choose another. */ #define M_USED 10 /* ERROR: %s does not exist. */ #define M_EXIST 11 /* ERROR: %s is not a valid %s. Choose another. */ #define M_INVALID 12 /* ERROR: %s is in use. Cannot %s it. */ #define M_BUSY 13 /* WARNING: %s has no permissions to use %s. */ #define M_NO_PERM 14 /* ERROR: There is not sufficient space to move %s home directory to %s */ #define M_NOSPACE 15 /* ERROR: %s %d is too big. Choose another. */ #define M_TOOBIG 16 /* ERROR: group %s does not exist. Choose another. */ #define M_GRP_NOTUSED 17 /* ERROR: Unable to %s: %s */ #define M_OOPS 18 /* ERROR: %s is not a full path name. Choose another. */ #define M_RELPATH 19 /* ERROR: %s is the primary group name. Choose another. */ #define M_SAME_GRP 20 /* ERROR: Inconsistent password files. See pwconv(8). */ #define M_HOSED_FILES 21 /* ERROR: %s is not a local user. */ #define M_NONLOCAL 22 /* ERROR: Permission denied. */ #define M_PERM_DENIED 23 /* WARNING: Group entry exceeds 2048 char: /etc/group entry truncated. */ #define M_GROUP_ENTRY_OVF 24 /* ERROR: invalid syntax.\nusage: roleadd ... */ #define M_ARUSAGE 25 /* ERROR: Invalid syntax.\nusage: roledel [-r] login\n" */ #define M_DRUSAGE 26 /* ERROR: Invalid syntax.\nusage: rolemod -u ... */ #define M_MRUSAGE 27 /* ERROR: project %s does not exist. Choose another. */ #define M_PROJ_NOTUSED 28 /* WARNING: more than NPROJECTS_MAX(%d) projects specified. */ #define M_MAXPROJECTS 29 /* WARNING: Project entry exceeds 512 char: /etc/project entry truncated. */ #define M_PROJ_ENTRY_OVF 30 /* ERROR: Invalid key. */ #define M_INVALID_KEY 31 /* ERROR: Missing value specification. */ #define M_INVALID_VALUE 32 /* ERROR: Multiple definitions of key ``%s''. */ #define M_REDEFINED_KEY 33 /* ERROR: Roles must be modified with rolemod */ #define M_ISROLE 34 /* ERROR: Users must be modified with usermod */ #define M_ISUSER 35 /* WARNING: gid %d is reserved. */ #define M_RESERVED_GID 36 /* ERROR: Failed to read /etc/group file due to invalid entry or read error. */ #define M_READ_ERROR 37 /* ERROR: %s is too long. Choose another. */ #define M_TOO_LONG 38 /* * WARNING: Avoided creating ZFS filesystem as parent directory * %s is not a ZFS mount point. */ #define M_NO_ZFS_MOUNTPOINT 39 #endif /* _MESSAGES_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include "messages.h" #include #include #include #define SBUFSZ 256 extern int access(), rm_files(); static char cmdbuf[SBUFSZ]; /* buffer for system call */ /* * Move directory contents from one place to another */ int move_dir(char *from, char *to, char *login, int flags) /* directory to move files from */ /* dirctory to move files to */ /* login id of owner */ /* miscellaneous flags */ { size_t len = 0; int rc = EX_SUCCESS; struct stat statbuf; struct utimbuf times; /* * ***** THIS IS WHERE SUFFICIENT SPACE CHECK GOES */ if (access(from, F_OK) == 0) { /* home dir exists */ /* move all files */ (void) sprintf(cmdbuf, "cd %s && find . -print | cpio -m -pd %s", from, to); if (system(cmdbuf) != 0) { errmsg(M_NOSPACE, from, to); return (EX_NOSPACE); } /* * Check that to dir is not a subdirectory of from */ len = strlen(from); if (strncmp(from, to, len) == 0 && strncmp(to+len, "/", 1) == 0) { errmsg(M_RMFILES); return (EX_HOMEDIR); } /* Retain the original permission and modification time */ if (stat(from, &statbuf) == 0) { chmod(to, statbuf.st_mode); times.actime = statbuf.st_atime; times.modtime = statbuf.st_mtime; (void) utime(to, ×); } /* Remove the files in the old place */ rc = rm_files(from, login, flags); } return (rc); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" int edit_project(char *login, char *new_login, projid_t projids[], int overwrite) { char **memptr; char t_name[] = "/etc/projtmp.XXXXXX"; FILE *e_fptr, *t_fptr; struct project *p_ptr; struct project p_work; char workbuf[NSS_LINELEN_PROJECT]; int i, modified = 0; struct stat sbuf; int p_length; char p_string[NSS_LINELEN_PROJECT]; long p_curr = 0; int exist; int fd; if ((e_fptr = fopen(PROJF_PATH, "r")) == NULL) { return (EX_UPDATE); } if (fstat(fileno(e_fptr), &sbuf) != 0) return (EX_UPDATE); if ((fd = mkstemp(t_name)) < 0) { return (EX_UPDATE); } if ((t_fptr = fdopen(fd, "w+")) == NULL) { (void) close(fd); (void) unlink(t_name); return (EX_UPDATE); } /* * Get ownership and permissions correct */ if (fchmod(fd, sbuf.st_mode) != 0 || fchown(fd, sbuf.st_uid, sbuf.st_gid) != 0) { (void) fclose(t_fptr); (void) unlink(t_name); return (EX_UPDATE); } p_curr = ftell(e_fptr); /* Make TMP file look like we want project file to look */ while (fgets(p_string, NSS_LINELEN_PROJECT - 1, e_fptr)) { /* While there is another group string */ p_length = strlen(p_string); (void) fseek(e_fptr, p_curr, SEEK_SET); p_ptr = fgetprojent(e_fptr, &p_work, &workbuf, sizeof (workbuf)); p_curr = ftell(e_fptr); if (p_ptr == NULL) { /* * tried to parse a proj string over * NSS_LINELEN_PROJECT chars */ errmsg(M_PROJ_ENTRY_OVF, NSS_LINELEN_PROJECT); modified = 0; /* bad project file: cannot rebuild */ break; } /* first delete the login from the project, if it's there */ if (overwrite || !projids) { if (p_ptr->pj_users != NULL) { for (memptr = p_ptr->pj_users; *memptr; memptr++) { if (strcmp(*memptr, login) == 0) { /* Delete this one */ char **from = memptr + 1; p_length -= (strlen(*memptr)+1); do { *(from - 1) = *from; } while (*from++); modified++; break; } } } } /* now check to see if project is one to add to */ if (projids) { for (i = 0; projids[i] != -1; i++) { if (p_ptr->pj_projid == projids[i]) { /* Scan for dups */ exist = 0; for (memptr = p_ptr->pj_users; *memptr; memptr++) { if (strncmp(*memptr, new_login ? new_login : login, strlen(*memptr)) == 0) exist++; } p_length += strlen(new_login ? new_login : login) + 1; if (p_length >= NSS_LINELEN_PROJECT - 1) { errmsg(M_PROJ_ENTRY_OVF, NSS_LINELEN_PROJECT); break; } else { if (!exist) { *memptr++ = new_login ? new_login : login; *memptr = NULL; modified++; } } } } } putprojent(p_ptr, t_fptr); } (void) fclose(e_fptr); (void) fclose(t_fptr); /* Now, update project file, if it was modified */ if (modified && rename(t_name, PROJF_PATH) < 0) { (void) unlink(t_name); return (EX_UPDATE); } (void) unlink(t_name); return (EX_SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2013 Gary Mills * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 RackTop Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" #include "userdisp.h" #include "funcs.h" /* * useradd [-u uid [-o] | -g group | -G group [[, group]...] * | -d dir [-m [-z|Z]] * | -s shell | -c comment | -k skel_dir | -b base_dir] ] * [ -A authorization [, authorization ...]] * [ -P profile [, profile ...]] * [ -K key=value ] * [ -R role [, role ...]] [-p project [, project ...]] login * useradd -D [ -g group ] [ -b base_dir | -f inactive | -e expire | * -s shell | -k skel_dir ] * [ -A authorization [, authorization ...]] * [ -P profile [, profile ...]] [ -K key=value ] * [ -R role [, role ...]] [-p project [, project ...]] login * * This command adds new user logins to the system. Arguments are: * * uid - an integer * group - an existing group's integer ID or char string name * dir - home directory * shell - a program to be used as a shell * comment - any text string * skel_dir - a skeleton directory * base_dir - a directory * login - a string of printable chars except colon(:) * authorization - One or more comma separated authorizations defined * in auth_attr(5). * profile - One or more comma separated execution profiles defined * in prof_attr(5) * role - One or more comma-separated role names defined in user_attr(5) * project - One or more comma-separated project names or numbers * */ extern struct userdefs *getusrdef(); extern void dispusrdef(); static void cleanup(); extern int check_perm(), valid_expire(); extern int putusrdef(), valid_uid(); extern int call_passmgmt(), edit_group(), create_home(); extern int edit_project(); extern int **valid_lgroup(); extern projid_t **valid_lproject(); extern void update_def(struct userdefs *); extern void import_def(struct userdefs *); extern int get_default_zfs_flags(); static uid_t uid; /* new uid */ static char *logname; /* login name to add */ static struct userdefs *usrdefs; /* defaults for useradd */ char *cmdname; static char homedir[ PATH_MAX + 1 ]; /* home directory */ static char gidstring[32]; /* group id string representation */ static gid_t gid; /* gid of new login */ static char uidstring[32]; /* user id string representation */ static char *uidstr = NULL; /* uid from command line */ static char *base_dir = NULL; /* base_dir from command line */ static char *group = NULL; /* group from command line */ static char *grps = NULL; /* multi groups from command line */ static char *dir = NULL; /* home dir from command line */ static char *shell = NULL; /* shell from command line */ static char *comment = NULL; /* comment from command line */ static char *skel_dir = NULL; /* skel dir from command line */ static long inact; /* inactive days */ static char *inactstr = NULL; /* inactive from command line */ static char inactstring[10]; /* inactivity string representation */ static char *expirestr = NULL; /* expiration date from command line */ static char *projects = NULL; /* project id's from command line */ static char *usertype = NULL; /* type of user, either role or normal */ typedef enum { BASEDIR = 0, SKELDIR, SHELL } path_opt_t; static void valid_input(path_opt_t, const char *); int main(argc, argv) int argc; char *argv[]; { int ch, ret, mflag = 0, oflag = 0, Dflag = 0; int zflag = 0, Zflag = 0, **gidlist = NULL; projid_t **projlist = NULL; char *ptr; /* loc in a str, may be set by strtol */ struct group *g_ptr; struct project p_ptr; char mybuf[PROJECT_BUFSZ]; struct stat statbuf; /* status buffer for stat */ int warning; int busy = 0; char **nargv; /* arguments for execvp of passmgmt */ int argindex; /* argument index into nargv */ int zfs_flags = 0; /* create_home flags */ cmdname = argv[0]; if (geteuid() != 0) { errmsg(M_PERM_DENIED); exit(EX_NO_PERM); } opterr = 0; /* no print errors from getopt */ usertype = getusertype(argv[0]); change_key(USERATTR_TYPE_KW, usertype); while ((ch = getopt(argc, argv, "b:c:Dd:e:f:G:g:k:mzZop:s:u:A:P:R:K:")) != EOF) switch (ch) { case 'b': base_dir = optarg; break; case 'c': comment = optarg; break; case 'D': Dflag++; break; case 'd': dir = optarg; break; case 'e': expirestr = optarg; break; case 'f': inactstr = optarg; break; case 'G': grps = optarg; break; case 'g': group = optarg; break; case 'k': skel_dir = optarg; break; case 'm': mflag++; break; case 'o': oflag++; break; case 'p': projects = optarg; break; case 's': shell = optarg; break; case 'u': uidstr = optarg; break; case 'Z': Zflag++; break; case 'z': zflag++; break; case 'A': change_key(USERATTR_AUTHS_KW, optarg); break; case 'P': change_key(USERATTR_PROFILES_KW, optarg); break; case 'R': if (is_role(usertype)) { errmsg(M_ARUSAGE); exit(EX_SYNTAX); } change_key(USERATTR_ROLES_KW, optarg); break; case 'K': change_key(NULL, optarg); break; default: case '?': if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); } if (((!mflag) && (zflag || Zflag)) || (zflag && Zflag) || (mflag > 1 && (zflag || Zflag))) { if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); } /* get defaults for adding new users */ usrdefs = getusrdef(usertype); if (Dflag) { /* DISPLAY mode */ /* check syntax */ if (optind != argc) { if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); } if (uidstr != NULL || oflag || grps != NULL || dir != NULL || mflag || comment != NULL) { if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); } /* Group must be an existing group */ if (group != NULL) { switch (valid_group(group, &g_ptr, &warning)) { case INVALID: errmsg(M_INVALID, group, "group id"); exit(EX_BADARG); /*NOTREACHED*/ case TOOBIG: errmsg(M_TOOBIG, "gid", group); exit(EX_BADARG); /*NOTREACHED*/ case RESERVED: case UNIQUE: errmsg(M_GRP_NOTUSED, group); exit(EX_NAME_NOT_EXIST); } if (warning) warningmsg(warning, group); usrdefs->defgroup = g_ptr->gr_gid; usrdefs->defgname = g_ptr->gr_name; } /* project must be an existing project */ if (projects != NULL) { switch (valid_project(projects, &p_ptr, mybuf, sizeof (mybuf), &warning)) { case INVALID: errmsg(M_INVALID, projects, "project id"); exit(EX_BADARG); /*NOTREACHED*/ case TOOBIG: errmsg(M_TOOBIG, "projid", projects); exit(EX_BADARG); /*NOTREACHED*/ case UNIQUE: errmsg(M_PROJ_NOTUSED, projects); exit(EX_NAME_NOT_EXIST); } if (warning) warningmsg(warning, projects); usrdefs->defproj = p_ptr.pj_projid; usrdefs->defprojname = p_ptr.pj_name; } /* base_dir must be an existing directory */ if (base_dir != NULL) { valid_input(BASEDIR, base_dir); usrdefs->defparent = base_dir; } /* inactivity period is an integer */ if (inactstr != NULL) { /* convert inactstr to integer */ inact = strtol(inactstr, &ptr, 10); if (*ptr || inact < 0) { errmsg(M_INVALID, inactstr, "inactivity period"); exit(EX_BADARG); } usrdefs->definact = inact; } /* expiration string is a date, newer than today */ if (expirestr != NULL) { if (*expirestr) { if (valid_expire(expirestr, (time_t *)0) == INVALID) { errmsg(M_INVALID, expirestr, "expiration date"); exit(EX_BADARG); } usrdefs->defexpire = expirestr; } else /* Unset the expiration date */ usrdefs->defexpire = ""; } if (shell != NULL) { valid_input(SHELL, shell); usrdefs->defshell = shell; } if (skel_dir != NULL) { valid_input(SKELDIR, skel_dir); usrdefs->defskel = skel_dir; } update_def(usrdefs); /* change defaults for useradd */ if (putusrdef(usrdefs, usertype) < 0) { errmsg(M_UPDATE, "created"); exit(EX_UPDATE); } /* Now, display */ dispusrdef(stdout, (D_ALL & ~D_RID), usertype); exit(EX_SUCCESS); } /* ADD mode */ /* check syntax */ if (optind != argc - 1 || (skel_dir != NULL && !mflag)) { if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); } logname = argv[optind]; switch (valid_login(logname, (struct passwd **)NULL, &warning)) { case INVALID: errmsg(M_INVALID, logname, "login name"); exit(EX_BADARG); /*NOTREACHED*/ case NOTUNIQUE: errmsg(M_USED, logname); exit(EX_NAME_EXISTS); /*NOTREACHED*/ case LONGNAME: errmsg(M_TOO_LONG, logname); exit(EX_BADARG); /*NOTREACHED*/ } if (warning) warningmsg(warning, logname); if (uidstr != NULL) { /* convert uidstr to integer */ errno = 0; uid = (uid_t)strtol(uidstr, &ptr, (int)10); if (*ptr || errno == ERANGE) { errmsg(M_INVALID, uidstr, "user id"); exit(EX_BADARG); } switch (valid_uid(uid, NULL)) { case NOTUNIQUE: if (!oflag) { /* override not specified */ errmsg(M_UID_USED, uid); exit(EX_ID_EXISTS); } break; case RESERVED: errmsg(M_RESERVED, uid); break; case TOOBIG: errmsg(M_TOOBIG, "uid", uid); exit(EX_BADARG); break; } } else { if (findnextuid(DEFRID+1, MAXUID, &uid) != 0) { errmsg(M_INVALID, "default id", "user id"); exit(EX_ID_EXISTS); } } if (group != NULL) { switch (valid_group(group, &g_ptr, &warning)) { case INVALID: errmsg(M_INVALID, group, "group id"); exit(EX_BADARG); /*NOTREACHED*/ case TOOBIG: errmsg(M_TOOBIG, "gid", group); exit(EX_BADARG); /*NOTREACHED*/ case RESERVED: case UNIQUE: errmsg(M_GRP_NOTUSED, group); exit(EX_NAME_NOT_EXIST); /*NOTREACHED*/ } if (warning) warningmsg(warning, group); gid = g_ptr->gr_gid; } else gid = usrdefs->defgroup; if (grps != NULL) { if (!*grps) /* ignore -G "" */ grps = (char *)0; else if (!(gidlist = valid_lgroup(grps, gid))) exit(EX_BADARG); } if (projects != NULL) { if (! *projects) projects = (char *)0; else if (! (projlist = valid_lproject(projects))) exit(EX_BADARG); } /* if base_dir is provided, check its validity; otherwise default */ if (base_dir != NULL) valid_input(BASEDIR, base_dir); else base_dir = usrdefs->defparent; if (dir == NULL) { /* set homedir to home directory made from base_dir */ (void) sprintf(homedir, "%s/%s", base_dir, logname); } else if (REL_PATH(dir)) { errmsg(M_RELPATH, dir); exit(EX_BADARG); } else (void) strcpy(homedir, dir); if (mflag) { /* Does home dir. already exist? */ if (stat(homedir, &statbuf) == 0) { /* directory exists - don't try to create */ mflag = 0; if (check_perm(statbuf, uid, gid, S_IXOTH) != 0) errmsg(M_NO_PERM, logname, homedir); } } /* * if shell, skel_dir are provided, check their validity. * Otherwise default. */ if (shell != NULL) valid_input(SHELL, shell); else shell = usrdefs->defshell; if (skel_dir != NULL) valid_input(SKELDIR, skel_dir); else skel_dir = usrdefs->defskel; if (inactstr != NULL) { /* convert inactstr to integer */ inact = strtol(inactstr, &ptr, 10); if (*ptr || inact < 0) { errmsg(M_INVALID, inactstr, "inactivity period"); exit(EX_BADARG); } } else inact = usrdefs->definact; /* expiration string is a date, newer than today */ if (expirestr != NULL) { if (*expirestr) { if (valid_expire(expirestr, (time_t *)0) == INVALID) { errmsg(M_INVALID, expirestr, "expiration date"); exit(EX_BADARG); } usrdefs->defexpire = expirestr; } else /* Unset the expiration date */ expirestr = (char *)0; } else expirestr = usrdefs->defexpire; import_def(usrdefs); /* must now call passmgmt */ /* set up arguments to passmgmt in nargv array */ nargv = malloc((30 + nkeys * 2) * sizeof (char *)); argindex = 0; nargv[argindex++] = PASSMGMT; nargv[argindex++] = "-a"; /* add */ if (comment != NULL) { /* comment */ nargv[argindex++] = "-c"; nargv[argindex++] = comment; } /* flags for home directory */ nargv[argindex++] = "-h"; nargv[argindex++] = homedir; /* set gid flag */ nargv[argindex++] = "-g"; (void) sprintf(gidstring, "%u", gid); nargv[argindex++] = gidstring; /* shell */ nargv[argindex++] = "-s"; nargv[argindex++] = shell; /* set inactive */ nargv[argindex++] = "-f"; (void) sprintf(inactstring, "%ld", inact); nargv[argindex++] = inactstring; /* set expiration date */ if (expirestr != NULL) { nargv[argindex++] = "-e"; nargv[argindex++] = expirestr; } /* set uid flag */ nargv[argindex++] = "-u"; (void) sprintf(uidstring, "%u", uid); nargv[argindex++] = uidstring; if (oflag) nargv[argindex++] = "-o"; if (nkeys > 1) addkey_args(nargv, &argindex); /* finally - login name */ nargv[argindex++] = logname; /* set the last to null */ nargv[argindex++] = NULL; /* now call passmgmt */ ret = PEX_FAILED; /* * If call_passmgmt fails for any reason other than PEX_BADUID, exit * is invoked with an appropriate error message. If PEX_BADUID is * returned, then if the user specified the ID, exit is invoked * with an appropriate error message. Otherwise we try to pick a * different ID and try again. If we run out of IDs, i.e. no more * users can be created, then -1 is returned and we terminate via exit. * If PEX_BUSY is returned we increment a count, since we will stop * trying if PEX_BUSY reaches 3. For PEX_SUCCESS we immediately * terminate the loop. */ while (busy < 3 && ret != PEX_SUCCESS) { switch (ret = call_passmgmt(nargv)) { case PEX_SUCCESS: break; case PEX_BUSY: busy++; break; case PEX_HOSED_FILES: errmsg(M_HOSED_FILES); exit(EX_INCONSISTENT); break; case PEX_SYNTAX: case PEX_BADARG: /* should NEVER occur that passmgmt usage is wrong */ if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); break; case PEX_BADUID: /* * The uid has been taken. If it was specified by a * user, then we must fail. Otherwise, keep trying * to get a good uid until we run out of IDs. */ if (uidstr != NULL) { errmsg(M_UID_USED, uid); exit(EX_ID_EXISTS); } else { if (findnextuid(DEFRID+1, MAXUID, &uid) != 0) { errmsg(M_INVALID, "default id", "user id"); exit(EX_ID_EXISTS); } (void) sprintf(uidstring, "%u", uid); } break; case PEX_BADNAME: /* invalid loname */ errmsg(M_USED, logname); exit(EX_NAME_EXISTS); break; default: errmsg(M_UPDATE, "created"); exit(ret); break; } } if (busy == 3) { errmsg(M_UPDATE, "created"); exit(ret); } /* add group entry */ if ((grps != NULL) && edit_group(logname, (char *)0, gidlist, 0)) { errmsg(M_UPDATE, "created"); cleanup(logname); exit(EX_UPDATE); } /* update project database */ if ((projects != NULL) && edit_project(logname, (char *)NULL, projlist, 0)) { errmsg(M_UPDATE, "created"); cleanup(logname); exit(EX_UPDATE); } /* create home directory */ if (mflag) { zfs_flags = get_default_zfs_flags(); if (zflag || mflag > 1) zfs_flags |= MANAGE_ZFS; else if (Zflag) zfs_flags &= ~MANAGE_ZFS; ret = create_home(homedir, skel_dir, uid, gid, zfs_flags); } if (ret != EX_SUCCESS) { (void) edit_project(logname, (char *)NULL, (projid_t **)NULL, 0); (void) edit_group(logname, (char *)0, (int **)0, 1); cleanup(logname); exit(EX_HOMEDIR); } return (ret); } static void cleanup(logname) char *logname; { char *nargv[4]; nargv[0] = PASSMGMT; nargv[1] = "-d"; nargv[2] = logname; nargv[3] = NULL; switch (call_passmgmt(nargv)) { case PEX_SUCCESS: break; case PEX_SYNTAX: /* should NEVER occur that passmgmt usage is wrong */ if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); break; case PEX_BADUID: /* uid is used - shouldn't happen but print message anyway */ errmsg(M_UID_USED, uid); break; case PEX_BADNAME: /* invalid loname */ errmsg(M_USED, logname); break; default: errmsg(M_UPDATE, "created"); break; } } /* Check the validity for shell, base_dir and skel_dir */ void valid_input(path_opt_t opt, const char *input) { struct stat statbuf; if (REL_PATH(input)) { errmsg(M_RELPATH, input); exit(EX_BADARG); } if (stat(input, &statbuf) == -1) { errmsg(M_INVALID, input, "path"); exit(EX_BADARG); } if (opt == SHELL) { if (!S_ISREG(statbuf.st_mode) || (statbuf.st_mode & 0555) != 0555) { errmsg(M_INVALID, input, "shell"); exit(EX_BADARG); } } else { if (!S_ISDIR(statbuf.st_mode)) { errmsg(M_INVALID, input, "directory"); exit(EX_BADARG); } } } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2013 Gary Mills # The EXCEED_TRAD indicates the action when the traditional login name # length limit of eight characters is exceeded. The value "warning" # means to issue a warning message and continue. This is the default. # The value "error" means to issue an error message and terminate. # The value "silent" means to continue without issuing any message. # EXCEED_TRAD=warning #EXCEED_TRAD=error #EXCEED_TRAD=silent # The MANAGE_ZFS indicates if ZFS create/destroy operations # should be performed by default when user passes -m flag to # userdel/usermod or -r flag to userdel MANAGE_ZFS=NO #MANAGE_ZFS=YES /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 RackTop Systems. * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include "userdisp.h" #include "funcs.h" #include "messages.h" /* Print out a NL when the line gets too long */ #define PRINTNL() \ if (outcount > 40) { \ outcount = 0; \ (void) fprintf(fptr, "\n"); \ } #define SKIPWS(ptr) while (*(ptr) == ' ' || *(ptr) == '\t') (ptr)++ static char *dup_to_nl(char *); static struct userdefs defaults = { DEFRID, DEFGROUP, DEFGNAME, DEFPARENT, DEFSKL, DEFSHL, DEFINACT, DEFEXPIRE, DEFAUTH, DEFPROF, DEFROLE, DEFPROJ, DEFPROJNAME, DEFLIMPRIV, DEFDFLTPRIV, DEFLOCK_AFTER_RETRIES, DEFROLEAUTH }; #define INT 0 #define STR 1 #define PROJID 2 #define DEFOFF(field) offsetof(struct userdefs, field) #define FIELD(up, pe, type) (*(type *)((char *)(up) + (pe)->off)) typedef struct parsent { const char *name; /* deffoo= */ const size_t nmsz; /* length of def= string (excluding \0) */ const int type; /* type of entry */ const ptrdiff_t off; /* offset in userdefs structure */ const char *uakey; /* user_attr key, if defined */ } parsent_t; static const parsent_t tab[] = { { GIDSTR, sizeof (GIDSTR) - 1, INT, DEFOFF(defgroup) }, { GNAMSTR, sizeof (GNAMSTR) - 1, STR, DEFOFF(defgname) }, { PARSTR, sizeof (PARSTR) - 1, STR, DEFOFF(defparent) }, { SKLSTR, sizeof (SKLSTR) - 1, STR, DEFOFF(defskel) }, { SHELLSTR, sizeof (SHELLSTR) - 1, STR, DEFOFF(defshell) }, { INACTSTR, sizeof (INACTSTR) - 1, INT, DEFOFF(definact) }, { EXPIRESTR, sizeof (EXPIRESTR) - 1, STR, DEFOFF(defexpire) }, { AUTHSTR, sizeof (AUTHSTR) - 1, STR, DEFOFF(defauth), USERATTR_AUTHS_KW }, { ROLESTR, sizeof (ROLESTR) - 1, STR, DEFOFF(defrole), USERATTR_ROLES_KW }, { PROFSTR, sizeof (PROFSTR) - 1, STR, DEFOFF(defprof), USERATTR_PROFILES_KW }, { PROJSTR, sizeof (PROJSTR) - 1, PROJID, DEFOFF(defproj) }, { PROJNMSTR, sizeof (PROJNMSTR) - 1, STR, DEFOFF(defprojname) }, { LIMPRSTR, sizeof (LIMPRSTR) - 1, STR, DEFOFF(deflimpriv), USERATTR_LIMPRIV_KW }, { DFLTPRSTR, sizeof (DFLTPRSTR) - 1, STR, DEFOFF(defdfltpriv), USERATTR_DFLTPRIV_KW }, { LOCK_AFTER_RETRIESSTR, sizeof (LOCK_AFTER_RETRIESSTR) - 1, STR, DEFOFF(deflock_after_retries), USERATTR_LOCK_AFTER_RETRIES_KW }, { ROLEAUTHSTR, sizeof (ROLEAUTHSTR) - 1, STR, DEFOFF(defroleauth), USERATTR_ROLEAUTH_KW }, }; #define NDEF (sizeof (tab) / sizeof (parsent_t)) FILE *defptr; /* default file - fptr */ static const parsent_t * scan(char **start_p) { static int ind = NDEF - 1; char *cur_p = *start_p; int lastind = ind; if (!*cur_p || *cur_p == '\n' || *cur_p == '#') return (NULL); /* * The magic in this loop is remembering the last index when * reentering the function; the entries above are also used to * order the output to the default file. */ do { ind++; ind %= NDEF; if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) { *start_p = cur_p + tab[ind].nmsz; return (&tab[ind]); } } while (ind != lastind); return (NULL); } /* * getusrdef - access the user defaults file. If it doesn't exist, * then returns default values of (values in userdefs.h): * defrid = 100 * defgroup = 1 * defgname = other * defparent = /home * defskel = /usr/sadm/skel * defshell = /bin/sh * definact = 0 * defexpire = 0 * defauth = 0 * defprof = 0 * defrole = 0 * defroleauth = role * * If getusrdef() is unable to access the defaults file, it * returns a NULL pointer. * * If user defaults file exists, then getusrdef uses values * in it to override the above values. */ struct userdefs * getusrdef(char *usertype) { char instr[512], *ptr; const parsent_t *pe; if (is_role(usertype)) { if ((defptr = fopen(DEFROLEFILE, "r")) == NULL) { defaults.defshell = DEFROLESHL; defaults.defprof = DEFROLEPROF; defaults.defroleauth = DEFROLEROLEAUTH; return (&defaults); } } else { if ((defptr = fopen(DEFFILE, "r")) == NULL) return (&defaults); } while (fgets(instr, sizeof (instr), defptr) != NULL) { ptr = instr; SKIPWS(ptr); if (*ptr == '#') continue; pe = scan(&ptr); if (pe != NULL) { switch (pe->type) { case INT: FIELD(&defaults, pe, int) = (int)strtol(ptr, NULL, 10); break; case PROJID: FIELD(&defaults, pe, projid_t) = (projid_t)strtol(ptr, NULL, 10); break; case STR: FIELD(&defaults, pe, char *) = dup_to_nl(ptr); break; } } } (void) fclose(defptr); return (&defaults); } static char * dup_to_nl(char *from) { char *res = strdup(from); char *p = strchr(res, '\n'); if (p) *p = '\0'; return (res); } void dispusrdef(FILE *fptr, unsigned flags, char *usertype) { struct userdefs *deflts = getusrdef(usertype); int outcount = 0; /* Print out values */ if (flags & D_GROUP) { outcount += fprintf(fptr, "group=%s,%ld ", deflts->defgname, deflts->defgroup); PRINTNL(); } if (flags & D_PROJ) { outcount += fprintf(fptr, "project=%s,%ld ", deflts->defprojname, deflts->defproj); PRINTNL(); } if (flags & D_BASEDIR) { outcount += fprintf(fptr, "basedir=%s ", deflts->defparent); PRINTNL(); } if (flags & D_RID) { outcount += fprintf(fptr, "rid=%ld ", deflts->defrid); PRINTNL(); } if (flags & D_SKEL) { outcount += fprintf(fptr, "skel=%s ", deflts->defskel); PRINTNL(); } if (flags & D_SHELL) { outcount += fprintf(fptr, "shell=%s ", deflts->defshell); PRINTNL(); } if (flags & D_INACT) { outcount += fprintf(fptr, "inactive=%d ", deflts->definact); PRINTNL(); } if (flags & D_EXPIRE) { outcount += fprintf(fptr, "expire=%s ", deflts->defexpire); PRINTNL(); } if (flags & D_AUTH) { outcount += fprintf(fptr, "auths=%s ", deflts->defauth); PRINTNL(); } if (flags & D_PROF) { outcount += fprintf(fptr, "profiles=%s ", deflts->defprof); PRINTNL(); } if ((flags & D_ROLE) && (!is_role(usertype))) { outcount += fprintf(fptr, "roles=%s ", deflts->defrole); PRINTNL(); } if (flags & D_LPRIV) { outcount += fprintf(fptr, "limitpriv=%s ", deflts->deflimpriv); PRINTNL(); } if (flags & D_DPRIV) { outcount += fprintf(fptr, "defaultpriv=%s ", deflts->defdfltpriv); PRINTNL(); } if (flags & D_LOCK) { outcount += fprintf(fptr, "lock_after_retries=%s ", deflts->deflock_after_retries); PRINTNL(); } if ((flags & D_ROLEAUTH) && is_role(usertype)) { outcount += fprintf(fptr, "roleauth=%s ", deflts->defroleauth); } if (outcount > 0) (void) fprintf(fptr, "\n"); } /* * putusrdef - * changes default values in defadduser file */ int putusrdef(struct userdefs *defs, char *usertype) { time_t timeval; /* time value from time */ int i; ptrdiff_t skip; char *hdr; /* * file format is: * #Default values for adduser. Changed mm/dd/yy hh:mm:ss. * defgroup=m (m=default group id) * defgname=str1 (str1=default group name) * defparent=str2 (str2=default base directory) * definactive=x (x=default inactive) * defexpire=y (y=default expire) * defproj=z (z=numeric project id) * defprojname=str3 (str3=default project name) * ... etc ... */ if (is_role(usertype)) { if ((defptr = fopen(DEFROLEFILE, "w")) == NULL) { errmsg(M_FAILED); return (EX_UPDATE); } } else { if ((defptr = fopen(DEFFILE, "w")) == NULL) { errmsg(M_FAILED); return (EX_UPDATE); } } if (lockf(fileno(defptr), F_LOCK, 0) != 0) { /* print error if can't lock whole of DEFFILE */ errmsg(M_UPDATE, "created"); return (EX_UPDATE); } if (is_role(usertype)) { /* If it's a role, we must skip the defrole field */ skip = DEFOFF(defrole); hdr = FHEADER_ROLE; } else { /* If it's a user, we must skip the defroleauth field */ skip = DEFOFF(defroleauth); hdr = FHEADER; } /* get time */ timeval = time(NULL); /* write it to file */ if (fprintf(defptr, "%s%s\n", hdr, ctime(&timeval)) <= 0) { errmsg(M_UPDATE, "created"); return (EX_UPDATE); } for (i = 0; i < NDEF; i++) { int res = 0; if (tab[i].off == skip) continue; switch (tab[i].type) { case INT: res = fprintf(defptr, "%s%d\n", tab[i].name, FIELD(defs, &tab[i], int)); break; case STR: res = fprintf(defptr, "%s%s\n", tab[i].name, FIELD(defs, &tab[i], char *)); break; case PROJID: res = fprintf(defptr, "%s%d\n", tab[i].name, (int)FIELD(defs, &tab[i], projid_t)); break; } if (res <= 0) { errmsg(M_UPDATE, "created"); return (EX_UPDATE); } } (void) lockf(fileno(defptr), F_ULOCK, 0); (void) fclose(defptr); return (EX_SUCCESS); } /* Export command line keys to defaults for useradd -D */ void update_def(struct userdefs *ud) { int i; for (i = 0; i < NDEF; i++) { char *val; if (tab[i].uakey != NULL && (val = getsetdefval(tab[i].uakey, NULL)) != NULL) FIELD(ud, &tab[i], char *) = val; } } /* Import default keys for ordinary useradd */ void import_def(struct userdefs *ud) { int i; for (i = 0; i < NDEF; i++) { if (tab[i].uakey != NULL && tab[i].type == STR) { char *val = FIELD(ud, &tab[i], char *); if (val == getsetdefval(tab[i].uakey, val)) nkeys ++; } } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" #include "funcs.h" /* * userdel [-r ] login * * This command deletes user logins. Arguments are: * * -r - when given, this option removes home directory & its contents * * login - a string of printable chars except colon (:) */ extern int check_perm(), isbusy(), get_default_zfs_flags(); extern int rm_files(), call_passmgmt(), edit_group(); static char *logname; /* login name to delete */ static char *nargv[20]; /* arguments for execvp of passmgmt */ char *cmdname; int main(int argc, char **argv) { int ch, ret = 0, rflag = 0; int zfs_flags = 0, argindex, tries; struct passwd *pstruct; struct stat statbuf; #ifndef att FILE *pwf; /* fille ptr for opened passwd file */ #endif char *usertype = NULL; int rc; cmdname = argv[0]; if (geteuid() != 0) { errmsg(M_PERM_DENIED); exit(EX_NO_PERM); } opterr = 0; /* no print errors from getopt */ usertype = getusertype(argv[0]); while ((ch = getopt(argc, argv, "r")) != EOF) { switch (ch) { case 'r': rflag++; break; case '?': if (is_role(usertype)) errmsg(M_DRUSAGE); else errmsg(M_DUSAGE); exit(EX_SYNTAX); } } if (optind != argc - 1) { if (is_role(usertype)) errmsg(M_DRUSAGE); else errmsg(M_DUSAGE); exit(EX_SYNTAX); } logname = argv[optind]; #ifdef att pstruct = getpwnam(logname); #else /* * Do this with fgetpwent to make sure we are only looking on local * system (since passmgmt only works on local system). */ if ((pwf = fopen("/etc/passwd", "r")) == NULL) { errmsg(M_OOPS, "open", "/etc/passwd"); exit(EX_FAILURE); } while ((pstruct = fgetpwent(pwf)) != NULL) if (strcmp(pstruct->pw_name, logname) == 0) break; fclose(pwf); #endif if (pstruct == NULL) { errmsg(M_EXIST, logname); exit(EX_NAME_NOT_EXIST); } if (isbusy(logname)) { errmsg(M_BUSY, logname, "remove"); exit(EX_BUSY); } /* that's it for validations - now do the work */ /* set up arguments to passmgmt in nargv array */ nargv[0] = PASSMGMT; nargv[1] = "-d"; /* delete */ argindex = 2; /* next argument */ /* finally - login name */ nargv[argindex++] = logname; /* set the last to null */ nargv[argindex++] = NULL; /* remove home directory */ if (rflag) { /* Check Permissions */ if (stat(pstruct->pw_dir, &statbuf)) { errmsg(M_OOPS, "find status about home directory", strerror(errno)); exit(EX_HOMEDIR); } if (check_perm(statbuf, pstruct->pw_uid, pstruct->pw_gid, S_IWOTH|S_IXOTH) != 0) { errmsg(M_NO_PERM, logname, pstruct->pw_dir); exit(EX_HOMEDIR); } zfs_flags = get_default_zfs_flags(); if (rm_files(pstruct->pw_dir, logname, zfs_flags) != EX_SUCCESS) exit(EX_HOMEDIR); } /* now call passmgmt */ ret = PEX_FAILED; for (tries = 3; ret != PEX_SUCCESS && tries--; ) { switch (ret = call_passmgmt(nargv)) { case PEX_SUCCESS: ret = edit_group(logname, (char *)0, (int **)0, 1); if (ret != EX_SUCCESS) errmsg(M_UPDATE, "deleted"); break; case PEX_BUSY: break; case PEX_HOSED_FILES: errmsg(M_HOSED_FILES); exit(EX_INCONSISTENT); break; case PEX_SYNTAX: case PEX_BADARG: /* should NEVER occur that passmgmt usage is wrong */ if (is_role(usertype)) errmsg(M_DRUSAGE); else errmsg(M_DUSAGE); exit(EX_SYNTAX); break; case PEX_BADUID: /* * uid is used - shouldn't happen but print message anyway */ errmsg(M_UID_USED, pstruct->pw_uid); exit(EX_ID_EXISTS); break; case PEX_BADNAME: /* invalid loname */ errmsg(M_USED, logname); exit(EX_NAME_EXISTS); break; default: errmsg(M_UPDATE, "deleted"); exit(ret); break; } } if (tries == 0) errmsg(M_UPDATE, "deleted"); /* * Now, remove this user from all project entries */ rc = edit_project(logname, (char *)0, (projid_t **)0, 1); if (rc != EX_SUCCESS) { errmsg(M_UPDATE, "modified"); exit(rc); } exit(ret); /*NOTREACHED*/ } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _USERDISP_H #define _USERDISP_H #ifdef __cplusplus extern "C" { #endif /* Flag values for dispusrdefs() */ #define D_GROUP 0x0001 #define D_BASEDIR 0x0002 #define D_RID 0x0004 #define D_SKEL 0x0008 #define D_SHELL 0x0010 #define D_INACT 0x0020 #define D_EXPIRE 0x0040 #define D_AUTH 0x0080 #define D_PROF 0x0100 #define D_ROLE 0x0200 #define D_PROJ 0x0400 #define D_LPRIV 0x0800 #define D_DPRIV 0x1000 #define D_LOCK 0x2000 #define D_ROLEAUTH 0x4000 #define D_ALL (D_GROUP | D_BASEDIR | D_RID | D_SKEL | D_SHELL \ | D_INACT | D_EXPIRE | D_AUTH | D_PROF | D_ROLE | D_PROJ | \ D_LPRIV | D_DPRIV | D_LOCK | D_ROLEAUTH) #ifdef __cplusplus } #endif #endif /* _USERDISP_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2013 Gary Mills * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 RackTop Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "users.h" #include "messages.h" #include "funcs.h" /* * usermod [-u uid [-o] | -g group | -G group [[,group]...] * | -d dir [-m [-z|Z]] * | -s shell | -c comment | -l new_logname] * | -f inactive | -e expire ] * [ -A authorization [, authorization ...]] * [ -P profile [, profile ...]] * [ -R role [, role ...]] * [ -K key=value ] * [ -p project [, project]] login * * This command adds new user logins to the system. Arguments are: * * uid - an integer less than MAXUID * group - an existing group's integer ID or char string name * dir - a directory * shell - a program to be used as a shell * comment - any text string * skel_dir - a directory * base_dir - a directory * rid - an integer less than 2**16 (USHORT) * login - a string of printable chars except colon (:) * inactive - number of days a login maybe inactive before it is locked * expire - date when a login is no longer valid * authorization - One or more comma separated authorizations defined * in auth_attr(5). * profile - One or more comma separated execution profiles defined * in prof_attr(5) * role - One or more comma-separated role names defined in user_attr(5) * key=value - One or more -K options each specifying a valid user_attr(5) * attribute. * */ extern int **valid_lgroup(), isbusy(), get_default_zfs_flags(); extern int valid_uid(), check_perm(), create_home(), move_dir(); extern int valid_expire(), edit_group(), call_passmgmt(); extern projid_t **valid_lproject(); static uid_t uid; /* new uid */ static gid_t gid; /* gid of new login */ static char *new_logname = NULL; /* new login name with -l option */ static char *uidstr = NULL; /* uid from command line */ static char *group = NULL; /* group from command line */ static char *grps = NULL; /* multi groups from command line */ static char *dir = NULL; /* home dir from command line */ static char *shell = NULL; /* shell from command line */ static char *comment = NULL; /* comment from command line */ static char *logname = NULL; /* login name to add */ static char *inactstr = NULL; /* inactive from command line */ static char *expire = NULL; /* expiration date from command line */ static char *projects = NULL; /* project ids from command line */ static char *usertype; char *cmdname; static char gidstring[32], uidstring[32]; char inactstring[10]; char * strcpmalloc(str) char *str; { if (str == NULL) return (NULL); return (strdup(str)); } struct passwd * passwd_cpmalloc(opw) struct passwd *opw; { struct passwd *npw; if (opw == NULL) return (NULL); npw = malloc(sizeof (struct passwd)); npw->pw_name = strcpmalloc(opw->pw_name); npw->pw_passwd = strcpmalloc(opw->pw_passwd); npw->pw_uid = opw->pw_uid; npw->pw_gid = opw->pw_gid; npw->pw_age = strcpmalloc(opw->pw_age); npw->pw_comment = strcpmalloc(opw->pw_comment); npw->pw_gecos = strcpmalloc(opw->pw_gecos); npw->pw_dir = strcpmalloc(opw->pw_dir); npw->pw_shell = strcpmalloc(opw->pw_shell); return (npw); } int main(argc, argv) int argc; char **argv; { int ch, ret = EX_SUCCESS, call_pass = 0, oflag = 0, zfs_flags = 0; int tries, mflag = 0, inact, **gidlist, flag = 0, zflag = 0, Zflag = 0; boolean_t fail_if_busy = B_FALSE; char *ptr; struct passwd *pstruct; /* password struct for login */ struct passwd *pw; struct group *g_ptr; /* validated group from -g */ struct stat statbuf; /* status buffer for stat */ #ifndef att FILE *pwf; /* fille ptr for opened passwd file */ #endif int warning; projid_t **projlist; char **nargv; /* arguments for execvp of passmgmt */ int argindex; /* argument index into nargv */ userattr_t *ua; char *val; int isrole; /* current account is role */ cmdname = argv[0]; if (geteuid() != 0) { errmsg(M_PERM_DENIED); exit(EX_NO_PERM); } opterr = 0; /* no print errors from getopt */ /* get user type based on the program name */ usertype = getusertype(argv[0]); while ((ch = getopt(argc, argv, "c:d:e:f:G:g:l:mzZop:s:u:A:P:R:K:")) != EOF) switch (ch) { case 'c': comment = optarg; flag++; break; case 'd': dir = optarg; fail_if_busy = B_TRUE; flag++; break; case 'e': expire = optarg; flag++; break; case 'f': inactstr = optarg; flag++; break; case 'G': grps = optarg; flag++; break; case 'g': group = optarg; fail_if_busy = B_TRUE; flag++; break; case 'l': new_logname = optarg; fail_if_busy = B_TRUE; flag++; break; case 'm': mflag++; flag++; fail_if_busy = B_TRUE; break; case 'o': oflag++; flag++; fail_if_busy = B_TRUE; break; case 'p': projects = optarg; flag++; break; case 's': shell = optarg; flag++; break; case 'u': uidstr = optarg; flag++; fail_if_busy = B_TRUE; break; case 'Z': Zflag++; break; case 'z': zflag++; break; case 'A': change_key(USERATTR_AUTHS_KW, optarg); flag++; break; case 'P': change_key(USERATTR_PROFILES_KW, optarg); flag++; break; case 'R': change_key(USERATTR_ROLES_KW, optarg); flag++; break; case 'K': change_key(NULL, optarg); flag++; break; default: case '?': if (is_role(usertype)) errmsg(M_MRUSAGE); else errmsg(M_MUSAGE); exit(EX_SYNTAX); } if (((!mflag) && (zflag || Zflag)) || (zflag && Zflag) || (mflag > 1 && (zflag || Zflag))) { if (is_role(usertype)) errmsg(M_ARUSAGE); else errmsg(M_AUSAGE); exit(EX_SYNTAX); } if (optind != argc - 1 || flag == 0) { if (is_role(usertype)) errmsg(M_MRUSAGE); else errmsg(M_MUSAGE); exit(EX_SYNTAX); } if ((!uidstr && oflag) || (mflag && !dir)) { if (is_role(usertype)) errmsg(M_MRUSAGE); else errmsg(M_MUSAGE); exit(EX_SYNTAX); } logname = argv[optind]; /* Determine whether the account is a role or not */ if ((ua = getusernam(logname)) == NULL || (val = kva_match(ua->attr, USERATTR_TYPE_KW)) == NULL || strcmp(val, USERATTR_TYPE_NONADMIN_KW) != 0) isrole = 0; else isrole = 1; /* Verify that rolemod is used for roles and usermod for users */ if (isrole != is_role(usertype)) { if (isrole) errmsg(M_ISROLE); else errmsg(M_ISUSER); exit(EX_SYNTAX); } /* Set the usertype key; defaults to the commandline */ usertype = getsetdefval(USERATTR_TYPE_KW, usertype); if (is_role(usertype)) { /* Roles can't have roles */ if (getsetdefval(USERATTR_ROLES_KW, NULL) != NULL) { errmsg(M_MRUSAGE); exit(EX_SYNTAX); } /* If it was an ordinary user, delete its roles */ if (!isrole) change_key(USERATTR_ROLES_KW, ""); } #ifdef att pw = getpwnam(logname); #else /* * Do this with fgetpwent to make sure we are only looking on local * system (since passmgmt only works on local system). */ if ((pwf = fopen("/etc/passwd", "r")) == NULL) { errmsg(M_OOPS, "open", "/etc/passwd"); exit(EX_FAILURE); } while ((pw = fgetpwent(pwf)) != NULL) if (strcmp(pw->pw_name, logname) == 0) break; fclose(pwf); #endif if (pw == NULL) { char pwdb[NSS_BUFLEN_PASSWD]; struct passwd pwd; if (getpwnam_r(logname, &pwd, pwdb, sizeof (pwdb)) == NULL) { /* This user does not exist. */ errmsg(M_EXIST, logname); exit(EX_NAME_NOT_EXIST); } else { /* This user exists in non-local name service. */ errmsg(M_NONLOCAL, logname); exit(EX_NOT_LOCAL); } } pstruct = passwd_cpmalloc(pw); /* * We can't modify a logged in user if any of the following * are being changed: * uid (-u & -o), group (-g), home dir (-m), loginname (-l). * If none of those are specified it is okay to go ahead * some types of changes only take effect on next login, some * like authorisations and profiles take effect instantly. * One might think that -K type=role should require that the * user not be logged in, however this would make it very * difficult to make the root account a role using this command. */ if (isbusy(logname)) { if (fail_if_busy) { errmsg(M_BUSY, logname, "change"); exit(EX_BUSY); } warningmsg(WARN_LOGGED_IN, logname); } if (new_logname && strcmp(new_logname, logname)) { switch (valid_login(new_logname, (struct passwd **)NULL, &warning)) { case INVALID: errmsg(M_INVALID, new_logname, "login name"); exit(EX_BADARG); /*NOTREACHED*/ case NOTUNIQUE: errmsg(M_USED, new_logname); exit(EX_NAME_EXISTS); /*NOTREACHED*/ case LONGNAME: errmsg(M_TOO_LONG, new_logname); exit(EX_BADARG); /*NOTREACHED*/ default: call_pass = 1; break; } if (warning) warningmsg(warning, logname); } if (uidstr) { /* convert uidstr to integer */ errno = 0; uid = (uid_t)strtol(uidstr, &ptr, (int)10); if (*ptr || errno == ERANGE) { errmsg(M_INVALID, uidstr, "user id"); exit(EX_BADARG); } if (uid != pstruct->pw_uid) { switch (valid_uid(uid, NULL)) { case NOTUNIQUE: if (!oflag) { /* override not specified */ errmsg(M_UID_USED, uid); exit(EX_ID_EXISTS); } break; case RESERVED: errmsg(M_RESERVED, uid); break; case TOOBIG: errmsg(M_TOOBIG, "uid", uid); exit(EX_BADARG); break; } call_pass = 1; } else { /* uid's the same, so don't change anything */ uidstr = NULL; oflag = 0; } } else uid = pstruct->pw_uid; if (group) { switch (valid_group(group, &g_ptr, &warning)) { case INVALID: errmsg(M_INVALID, group, "group id"); exit(EX_BADARG); /*NOTREACHED*/ case TOOBIG: errmsg(M_TOOBIG, "gid", group); exit(EX_BADARG); /*NOTREACHED*/ case UNIQUE: errmsg(M_GRP_NOTUSED, group); exit(EX_NAME_NOT_EXIST); /*NOTREACHED*/ case RESERVED: gid = (gid_t)strtol(group, &ptr, (int)10); errmsg(M_RESERVED_GID, gid); break; } if (warning) warningmsg(warning, group); if (g_ptr != NULL) gid = g_ptr->gr_gid; else gid = pstruct->pw_gid; /* call passmgmt if gid is different, else ignore group */ if (gid != pstruct->pw_gid) call_pass = 1; else group = NULL; } else gid = pstruct->pw_gid; if (grps && *grps) { if (!(gidlist = valid_lgroup(grps, gid))) exit(EX_BADARG); } else gidlist = (int **)0; if (projects && *projects) { if (! (projlist = valid_lproject(projects))) exit(EX_BADARG); } else projlist = (projid_t **)0; if (dir) { if (REL_PATH(dir)) { errmsg(M_RELPATH, dir); exit(EX_BADARG); } if (strcmp(pstruct->pw_dir, dir) == 0) { /* home directory is the same so ignore dflag & mflag */ dir = NULL; mflag = 0; } else call_pass = 1; } if (mflag) { if (stat(dir, &statbuf) == 0) { /* Home directory exists */ if (check_perm(statbuf, pstruct->pw_uid, pstruct->pw_gid, S_IWOTH|S_IXOTH) != 0) { errmsg(M_NO_PERM, logname, dir); exit(EX_NO_PERM); } } else { zfs_flags = get_default_zfs_flags(); if (zflag || mflag > 1) zfs_flags |= MANAGE_ZFS; else if (Zflag) zfs_flags &= ~MANAGE_ZFS; ret = create_home(dir, NULL, uid, gid, zfs_flags); } if (ret == EX_SUCCESS) ret = move_dir(pstruct->pw_dir, dir, logname, zfs_flags); if (ret != EX_SUCCESS) exit(ret); } if (shell) { if (REL_PATH(shell)) { errmsg(M_RELPATH, shell); exit(EX_BADARG); } if (strcmp(pstruct->pw_shell, shell) == 0) { /* ignore s option if shell is not different */ shell = NULL; } else { if (stat(shell, &statbuf) < 0 || (statbuf.st_mode & S_IFMT) != S_IFREG || (statbuf.st_mode & 0555) != 0555) { errmsg(M_INVALID, shell, "shell"); exit(EX_BADARG); } call_pass = 1; } } if (comment) { /* ignore comment if comment is not changed */ if (strcmp(pstruct->pw_comment, comment)) call_pass = 1; else comment = NULL; } /* inactive string is a positive integer */ if (inactstr) { /* convert inactstr to integer */ inact = (int)strtol(inactstr, &ptr, 10); if (*ptr || inact < 0) { errmsg(M_INVALID, inactstr, "inactivity period"); exit(EX_BADARG); } call_pass = 1; } /* expiration string is a date, newer than today */ if (expire) { if (*expire && valid_expire(expire, (time_t *)0) == INVALID) { errmsg(M_INVALID, expire, "expiration date"); exit(EX_BADARG); } call_pass = 1; } if (nkeys > 0) call_pass = 1; /* that's it for validations - now do the work */ if (grps) { /* redefine login's supplentary group memberships */ ret = edit_group(logname, new_logname, gidlist, 1); if (ret != EX_SUCCESS) { errmsg(M_UPDATE, "modified"); exit(ret); } } if (projects) { ret = edit_project(logname, (char *)NULL, projlist, 0); if (ret != EX_SUCCESS) { errmsg(M_UPDATE, "modified"); exit(ret); } } if (!call_pass) exit(ret); /* only get to here if need to call passmgmt */ /* set up arguments to passmgmt in nargv array */ nargv = malloc((30 + nkeys * 2) * sizeof (char *)); argindex = 0; nargv[argindex++] = PASSMGMT; nargv[argindex++] = "-m"; /* modify */ if (comment) { /* comment */ nargv[argindex++] = "-c"; nargv[argindex++] = comment; } if (dir) { /* flags for home directory */ nargv[argindex++] = "-h"; nargv[argindex++] = dir; } if (group) { /* set gid flag */ nargv[argindex++] = "-g"; (void) sprintf(gidstring, "%u", gid); nargv[argindex++] = gidstring; } if (shell) { /* shell */ nargv[argindex++] = "-s"; nargv[argindex++] = shell; } if (inactstr) { nargv[argindex++] = "-f"; nargv[argindex++] = inactstr; } if (expire) { nargv[argindex++] = "-e"; nargv[argindex++] = expire; } if (uidstr) { /* set uid flag */ nargv[argindex++] = "-u"; (void) sprintf(uidstring, "%u", uid); nargv[argindex++] = uidstring; } if (oflag) nargv[argindex++] = "-o"; if (new_logname) { /* redefine login name */ nargv[argindex++] = "-l"; nargv[argindex++] = new_logname; } if (nkeys > 0) addkey_args(nargv, &argindex); /* finally - login name */ nargv[argindex++] = logname; /* set the last to null */ nargv[argindex++] = NULL; /* now call passmgmt */ ret = PEX_FAILED; for (tries = 3; ret != PEX_SUCCESS && tries--; ) { switch (ret = call_passmgmt(nargv)) { case PEX_SUCCESS: case PEX_BUSY: break; case PEX_HOSED_FILES: errmsg(M_HOSED_FILES); exit(EX_INCONSISTENT); break; case PEX_SYNTAX: case PEX_BADARG: /* should NEVER occur that passmgmt usage is wrong */ if (is_role(usertype)) errmsg(M_MRUSAGE); else errmsg(M_MUSAGE); exit(EX_SYNTAX); break; case PEX_BADUID: /* uid in use - shouldn't happen print message anyway */ errmsg(M_UID_USED, uid); exit(EX_ID_EXISTS); break; case PEX_BADNAME: /* invalid loname */ errmsg(M_USED, logname); exit(EX_NAME_EXISTS); break; default: errmsg(M_UPDATE, "modified"); exit(ret); break; } } if (tries == 0) { errmsg(M_UPDATE, "modified"); } exit(ret); /*NOTREACHED*/ } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 RackTop Systems. */ #include #include #include #include #include #include #include #include "messages.h" extern void exit(); extern char *strtok(); static gid_t *grplist; static int ngroups_max = 0; /* Validate a list of groups */ int ** valid_lgroup(char *list, gid_t gid) { int n_invalid = 0, i = 0, j; char *ptr; struct group *g_ptr; int warning; int dup_prim = 0; /* we don't duplicate our primary as a supplemental */ if( !list || !*list ) return( (int **) NULL ); if (ngroups_max == 0) { ngroups_max = sysconf(_SC_NGROUPS_MAX); grplist = malloc((ngroups_max + 1) * sizeof (gid_t)); } while ((ptr = strtok((i || n_invalid || dup_prim)? NULL: list, ","))) { switch (valid_group(ptr, &g_ptr, &warning)) { case INVALID: errmsg( M_INVALID, ptr, "group id" ); n_invalid++; break; case TOOBIG: errmsg( M_TOOBIG, "gid", ptr ); n_invalid++; break; case UNIQUE: errmsg( M_GRP_NOTUSED, ptr ); n_invalid++; break; case NOTUNIQUE: /* ignore duplicated primary */ if (g_ptr->gr_gid == gid) { if (!dup_prim) dup_prim++; continue; } if( !i ) grplist[ i++ ] = g_ptr->gr_gid; else { /* Keep out duplicates */ for( j = 0; j < i; j++ ) if( g_ptr->gr_gid == grplist[j] ) break; if( j == i ) /* Not a duplicate */ grplist[i++] = g_ptr->gr_gid; } break; } if (warning) warningmsg(warning, ptr); if( i >= ngroups_max ) { errmsg( M_MAXGROUPS, ngroups_max ); break; } } /* Terminate the list */ grplist[ i ] = -1; if( n_invalid ) exit( EX_BADARG ); return( (int **)grplist ); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013 RackTop Systems. */ #include #include #include #include #include #include #include #include #include "messages.h" static projid_t projlist[NPROJECTS_MAX + 1]; static int nproj_max = NPROJECTS_MAX; /* Validate a list of projects */ int ** valid_lproject(char *list) { int n_invalid = 0; int i = 0; int j; char *ptr; struct project projent; int warning; char mybuf[PROJECT_BUFSZ]; if (!list || !*list) return ((int **)NULL); while ((ptr = strtok((i || n_invalid) ? NULL : list, ","))) { switch (valid_project(ptr, &projent, mybuf, sizeof (mybuf), &warning)) { case INVALID: errmsg(M_INVALID, ptr, "project id"); n_invalid++; break; case TOOBIG: errmsg(M_TOOBIG, "projid", ptr); n_invalid++; break; case UNIQUE: errmsg(M_PROJ_NOTUSED, ptr); n_invalid++; break; case NOTUNIQUE: if (!i) /* ignore respecified primary */ projlist[i++] = projent.pj_projid; else { /* Keep out duplicates */ for (j = 0; j < i; j++) if (projent.pj_projid == projlist[j]) break; if (j == i) /* Not a duplicate */ projlist[i++] = projent.pj_projid; } break; } if (warning) warningmsg(warning, ptr); if (i >= nproj_max) { errmsg(M_MAXPROJECTS, nproj_max); break; } } /* Terminate the list */ projlist[i] = -1; if (n_invalid) exit(EX_BADARG); return ((int **)projlist); }