1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 33*7c478bd9Sstevel@tonic-gate #include <stdio.h> 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <string.h> 36*7c478bd9Sstevel@tonic-gate #include <ctype.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 38*7c478bd9Sstevel@tonic-gate #include <grp.h> 39*7c478bd9Sstevel@tonic-gate #include <unistd.h> 40*7c478bd9Sstevel@tonic-gate #include <userdefs.h> 41*7c478bd9Sstevel@tonic-gate #include <errno.h> 42*7c478bd9Sstevel@tonic-gate #include <limits.h> 43*7c478bd9Sstevel@tonic-gate #include "users.h" 44*7c478bd9Sstevel@tonic-gate #include "messages.h" 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #define MYBUFSIZE (LINE_MAX) 47*7c478bd9Sstevel@tonic-gate /* Corresponds to MYBUFSIZE in grpck.c, BUFCONST in nss_dbdefs.c */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate int 50*7c478bd9Sstevel@tonic-gate edit_group(char *login, char *new_login, gid_t gids[], int overwrite) 51*7c478bd9Sstevel@tonic-gate { 52*7c478bd9Sstevel@tonic-gate char **memptr; 53*7c478bd9Sstevel@tonic-gate char t_name[] = "/etc/gtmp.XXXXXX"; 54*7c478bd9Sstevel@tonic-gate int fd; 55*7c478bd9Sstevel@tonic-gate FILE *e_fptr, *t_fptr; 56*7c478bd9Sstevel@tonic-gate struct group *g_ptr; /* group structure from fgetgrent */ 57*7c478bd9Sstevel@tonic-gate int i; 58*7c478bd9Sstevel@tonic-gate int modified = 0; 59*7c478bd9Sstevel@tonic-gate struct stat sbuf; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate int bufsize, g_length, sav_errno; 62*7c478bd9Sstevel@tonic-gate long g_curr = 0L; 63*7c478bd9Sstevel@tonic-gate char *g_string, *new_g_string, *gstr_off; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate if ((e_fptr = fopen(GROUP, "r")) == NULL) 66*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate if (fstat(fileno(e_fptr), &sbuf) != 0) { 69*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 70*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 71*7c478bd9Sstevel@tonic-gate } 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate if ((fd = mkstemp(t_name)) == -1) { 74*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 75*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 76*7c478bd9Sstevel@tonic-gate } 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate if ((t_fptr = fdopen(fd, "w")) == NULL) { 79*7c478bd9Sstevel@tonic-gate (void) close(fd); 80*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 81*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 82*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 83*7c478bd9Sstevel@tonic-gate } 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /* 86*7c478bd9Sstevel@tonic-gate * Get ownership and permissions correct 87*7c478bd9Sstevel@tonic-gate */ 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate if (fchmod(fd, sbuf.st_mode) != 0 || 90*7c478bd9Sstevel@tonic-gate fchown(fd, sbuf.st_uid, sbuf.st_gid) != 0) { 91*7c478bd9Sstevel@tonic-gate (void) fclose(t_fptr); 92*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 93*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 94*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 95*7c478bd9Sstevel@tonic-gate } 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate g_curr = ftell(e_fptr); 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* Make TMP file look like we want GROUP file to look */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate bufsize = MYBUFSIZE; 102*7c478bd9Sstevel@tonic-gate if ((g_string = malloc(bufsize)) == NULL) { 103*7c478bd9Sstevel@tonic-gate (void) fclose(t_fptr); 104*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 105*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 106*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate * bufsize contains the size of the currently allocated buffer 110*7c478bd9Sstevel@tonic-gate * buffer size, which is initially MYBUFSIZE but when a line 111*7c478bd9Sstevel@tonic-gate * greater than MYBUFSIZE is encountered then bufsize gets increased 112*7c478bd9Sstevel@tonic-gate * by MYBUFSIZE. 113*7c478bd9Sstevel@tonic-gate * g_string always points to the beginning of the buffer (even after 114*7c478bd9Sstevel@tonic-gate * realloc()). 115*7c478bd9Sstevel@tonic-gate * gstr_off = g_string + MYBUFSIZE * (n), where n >= 0. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate while (!feof(e_fptr) && !ferror(e_fptr)) { 118*7c478bd9Sstevel@tonic-gate g_length = 0; 119*7c478bd9Sstevel@tonic-gate gstr_off = g_string; 120*7c478bd9Sstevel@tonic-gate while (fgets(gstr_off, (bufsize - g_length), e_fptr) != NULL) { 121*7c478bd9Sstevel@tonic-gate g_length += strlen(gstr_off); 122*7c478bd9Sstevel@tonic-gate if (g_string[g_length - 1] == '\n' || feof(e_fptr)) 123*7c478bd9Sstevel@tonic-gate break; 124*7c478bd9Sstevel@tonic-gate new_g_string = realloc(g_string, (bufsize + MYBUFSIZE)); 125*7c478bd9Sstevel@tonic-gate if (new_g_string == NULL) { 126*7c478bd9Sstevel@tonic-gate free(g_string); 127*7c478bd9Sstevel@tonic-gate (void) fclose(t_fptr); 128*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 129*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 130*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate bufsize += MYBUFSIZE; 133*7c478bd9Sstevel@tonic-gate g_string = new_g_string; 134*7c478bd9Sstevel@tonic-gate gstr_off = g_string + g_length; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate if (g_length == 0) { 137*7c478bd9Sstevel@tonic-gate continue; 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* While there is another group string */ 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate (void) fseek(e_fptr, g_curr, SEEK_SET); 143*7c478bd9Sstevel@tonic-gate errno = 0; 144*7c478bd9Sstevel@tonic-gate g_ptr = fgetgrent(e_fptr); 145*7c478bd9Sstevel@tonic-gate sav_errno = errno; 146*7c478bd9Sstevel@tonic-gate g_curr = ftell(e_fptr); 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate if (g_ptr == NULL) { 149*7c478bd9Sstevel@tonic-gate /* tried to parse a group string over MYBUFSIZ char */ 150*7c478bd9Sstevel@tonic-gate if (sav_errno == ERANGE) 151*7c478bd9Sstevel@tonic-gate errmsg(M_GROUP_ENTRY_OVF); 152*7c478bd9Sstevel@tonic-gate else 153*7c478bd9Sstevel@tonic-gate errmsg(M_READ_ERROR); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate modified = 0; /* bad group file: cannot rebuild */ 156*7c478bd9Sstevel@tonic-gate break; 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate /* first delete the login from the group, if it's there */ 160*7c478bd9Sstevel@tonic-gate if (overwrite || !gids) { 161*7c478bd9Sstevel@tonic-gate if (g_ptr->gr_mem != NULL) { 162*7c478bd9Sstevel@tonic-gate for (memptr = g_ptr->gr_mem; *memptr; 163*7c478bd9Sstevel@tonic-gate memptr++) { 164*7c478bd9Sstevel@tonic-gate if (strcmp(*memptr, login) == 0) { 165*7c478bd9Sstevel@tonic-gate /* Delete this one */ 166*7c478bd9Sstevel@tonic-gate char **from = memptr + 1; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate g_length -= (strlen(*memptr)+1); 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate do { 171*7c478bd9Sstevel@tonic-gate *(from - 1) = *from; 172*7c478bd9Sstevel@tonic-gate } while (*from++); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate modified++; 175*7c478bd9Sstevel@tonic-gate break; 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* now check to see if group is one to add to */ 182*7c478bd9Sstevel@tonic-gate if (gids) { 183*7c478bd9Sstevel@tonic-gate for (i = 0; gids[i] != -1; i++) { 184*7c478bd9Sstevel@tonic-gate if (g_ptr->gr_gid == gids[i]) { 185*7c478bd9Sstevel@tonic-gate /* Find end */ 186*7c478bd9Sstevel@tonic-gate for (memptr = g_ptr->gr_mem; *memptr; 187*7c478bd9Sstevel@tonic-gate memptr++) 188*7c478bd9Sstevel@tonic-gate ; 189*7c478bd9Sstevel@tonic-gate g_length += strlen(new_login ? 190*7c478bd9Sstevel@tonic-gate new_login : login)+1; 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate *memptr++ = new_login ? 193*7c478bd9Sstevel@tonic-gate new_login : login; 194*7c478bd9Sstevel@tonic-gate *memptr = NULL; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate modified++; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate putgrent(g_ptr, t_fptr); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate free(g_string); 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate (void) fclose(e_fptr); 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate if (fclose(t_fptr) != 0) { 207*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 208*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate /* Now, update GROUP file, if it was modified */ 212*7c478bd9Sstevel@tonic-gate if (modified) { 213*7c478bd9Sstevel@tonic-gate if (rename(t_name, GROUP) != 0) { 214*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 215*7c478bd9Sstevel@tonic-gate return (EX_UPDATE); 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate return (EX_SUCCESS); 218*7c478bd9Sstevel@tonic-gate } else { 219*7c478bd9Sstevel@tonic-gate (void) unlink(t_name); 220*7c478bd9Sstevel@tonic-gate return (EX_SUCCESS); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate } 223