pw_conf.c revision 20302
120253Sjoerg/*- 220302Sjoerg * Copyright (C) 1996 320302Sjoerg * David L. Nugent. All rights reserved. 420253Sjoerg * 520253Sjoerg * Redistribution and use in source and binary forms, with or without 620253Sjoerg * modification, are permitted provided that the following conditions 720253Sjoerg * are met: 820253Sjoerg * 1. Redistributions of source code must retain the above copyright 920302Sjoerg * notice, this list of conditions and the following disclaimer. 1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1120253Sjoerg * notice, this list of conditions and the following disclaimer in the 1220253Sjoerg * documentation and/or other materials provided with the distribution. 1320253Sjoerg * 1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1720302Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2420253Sjoerg * SUCH DAMAGE. 2520253Sjoerg * 2620302Sjoerg * $Id: pw_conf.c,v 1.1.1.1 1996/12/09 14:05:35 joerg Exp $ 2720253Sjoerg */ 2820253Sjoerg 2920253Sjoerg#include <string.h> 3020253Sjoerg#include <ctype.h> 3120253Sjoerg#include <fcntl.h> 3220253Sjoerg 3320253Sjoerg#include "pw.h" 3420253Sjoerg 3520253Sjoerg#define debugging 0 3620253Sjoerg 3720253Sjoergenum { 3820253Sjoerg _UC_NONE, 3920253Sjoerg _UC_DEFAULTPWD, 4020253Sjoerg _UC_REUSEUID, 4120253Sjoerg _UC_REUSEGID, 4220253Sjoerg _UC_DOTDIR, 4320253Sjoerg _UC_NEWMAIL, 4420253Sjoerg _UC_LOGFILE, 4520253Sjoerg _UC_HOMEROOT, 4620253Sjoerg _UC_SHELLPATH, 4720253Sjoerg _UC_SHELLS, 4820253Sjoerg _UC_DEFAULTSHELL, 4920253Sjoerg _UC_DEFAULTGROUP, 5020253Sjoerg _UC_EXTRAGROUPS, 5120253Sjoerg _UC_DEFAULTCLASS, 5220253Sjoerg _UC_MINUID, 5320253Sjoerg _UC_MAXUID, 5420253Sjoerg _UC_MINGID, 5520253Sjoerg _UC_MAXGID, 5620253Sjoerg _UC_EXPIRE, 5720253Sjoerg _UC_PASSWORD, 5820253Sjoerg _UC_FIELDS 5920253Sjoerg}; 6020253Sjoerg 6120253Sjoergstatic char bourne_shell[] = "sh"; 6220253Sjoerg 6320253Sjoergstatic char *system_shells[_UC_MAXSHELLS] = 6420253Sjoerg{ 6520253Sjoerg bourne_shell, 6620253Sjoerg "csh" 6720253Sjoerg}; 6820253Sjoerg 6920253Sjoergstatic char *default_groups[_UC_MAXGROUPS] = 7020253Sjoerg{ 7120253Sjoerg NULL 7220253Sjoerg}; 7320253Sjoerg 7420253Sjoergstatic char const *booltrue[] = 7520253Sjoerg{ 7620253Sjoerg "yes", "true", "1", "on", NULL 7720253Sjoerg}; 7820253Sjoergstatic char const *boolfalse[] = 7920253Sjoerg{ 8020253Sjoerg "no", "false", "0", "off", NULL 8120253Sjoerg}; 8220253Sjoerg 8320253Sjoergstatic struct userconf config = 8420253Sjoerg{ 8520253Sjoerg 0, /* Default password for new users? (nologin) */ 8620253Sjoerg 0, /* Reuse uids? */ 8720253Sjoerg 0, /* Reuse gids? */ 8820253Sjoerg "/usr/share/skel", /* Where to obtain skeleton files */ 8920253Sjoerg NULL, /* Mail to send to new accounts */ 9020253Sjoerg "/var/log/userlog", /* Where to log changes */ 9120253Sjoerg "/home", /* Where to create home directory */ 9220253Sjoerg "/bin", /* Where shells are located */ 9320253Sjoerg system_shells, /* List of shells (first is default) */ 9420253Sjoerg bourne_shell, /* Default shell */ 9520253Sjoerg NULL, /* Default group name */ 9620253Sjoerg default_groups, /* Default (additional) groups */ 9720253Sjoerg NULL, /* Default login class */ 9820253Sjoerg 1000, 32000, /* Allowed range of uids */ 9920253Sjoerg 1000, 32000, /* Allowed range of gids */ 10020253Sjoerg 0, /* Days until account expires */ 10120253Sjoerg 0 /* Days until password expires */ 10220253Sjoerg}; 10320253Sjoerg 10420253Sjoergstatic char const *comments[_UC_FIELDS] = 10520253Sjoerg{ 10620253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 10720253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 10820253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 10920253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11020253Sjoerg "\n# Obtain default dotfiles from this directory\n", 11120253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 11220253Sjoerg "\n# Log add/change/remove information in this file\n", 11320253Sjoerg "\n# Root directory in which $HOME directory is created\n", 11420253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 11520253Sjoerg "\n# Space separated list of available shells (without paths)\n", 11620253Sjoerg "\n# Default shell (without path)\n", 11720253Sjoerg "\n# Default group (leave blank for new group per user)\n", 11820253Sjoerg "\n# Extra groups for new users\n", 11920253Sjoerg "\n# Default login class for new users\n", 12020253Sjoerg "\n# Range of valid default user ids\n", 12120253Sjoerg NULL, 12220253Sjoerg "\n# Range of valid default group ids\n", 12320253Sjoerg NULL, 12420253Sjoerg "\n# Days after which account expires (0=disabled)\n", 12520253Sjoerg "\n# Days after which password expires (0=disabled)\n" 12620253Sjoerg}; 12720253Sjoerg 12820253Sjoergstatic char const *kwds[] = 12920253Sjoerg{ 13020253Sjoerg "", 13120253Sjoerg "defaultpasswd", 13220253Sjoerg "reuseuids", 13320253Sjoerg "reusegids", 13420253Sjoerg "skeleton", 13520253Sjoerg "newmail", 13620253Sjoerg "logfile", 13720253Sjoerg "home", 13820253Sjoerg "shellpath", 13920253Sjoerg "shells", 14020253Sjoerg "defaultshell", 14120253Sjoerg "defaultgroup", 14220253Sjoerg "extragroups", 14320253Sjoerg "defaultclass", 14420253Sjoerg "minuid", 14520253Sjoerg "maxuid", 14620253Sjoerg "mingid", 14720253Sjoerg "maxgid", 14820253Sjoerg "expire_days", 14920253Sjoerg "password_days", 15020253Sjoerg NULL 15120253Sjoerg}; 15220253Sjoerg 15320253Sjoergstatic char * 15420253Sjoergunquote(char const * str) 15520253Sjoerg{ 15620253Sjoerg if (str && (*str == '"' || *str == '\'')) { 15720253Sjoerg char *p = strchr(str + 1, *str); 15820253Sjoerg 15920253Sjoerg if (p != NULL) 16020253Sjoerg *p = '\0'; 16120253Sjoerg return (char *) (*++str ? str : NULL); 16220253Sjoerg } 16320253Sjoerg return (char *) str; 16420253Sjoerg} 16520253Sjoerg 16620253Sjoergint 16720253Sjoergboolean_val(char const * str, int dflt) 16820253Sjoerg{ 16920253Sjoerg if ((str = unquote(str)) != NULL) { 17020253Sjoerg int i; 17120253Sjoerg 17220253Sjoerg for (i = 0; booltrue[i]; i++) 17320253Sjoerg if (strcmp(str, booltrue[i]) == 0) 17420253Sjoerg return 1; 17520253Sjoerg for (i = 0; boolfalse[i]; i++) 17620253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 17720253Sjoerg return 0; 17820253Sjoerg 17920253Sjoerg /* 18020253Sjoerg * Special cases for defaultpassword 18120253Sjoerg */ 18220253Sjoerg if (strcmp(str, "random") == 0) 18320253Sjoerg return -1; 18420253Sjoerg if (strcmp(str, "none") == 0) 18520253Sjoerg return -2; 18620253Sjoerg } 18720253Sjoerg return dflt; 18820253Sjoerg} 18920253Sjoerg 19020253Sjoergchar const * 19120253Sjoergboolean_str(int val) 19220253Sjoerg{ 19320253Sjoerg if (val == -1) 19420253Sjoerg return "random"; 19520253Sjoerg else if (val == -2) 19620253Sjoerg return "none"; 19720253Sjoerg else 19820253Sjoerg return val ? booltrue[0] : boolfalse[0]; 19920253Sjoerg} 20020253Sjoerg 20120253Sjoergchar * 20220253Sjoergnewstr(char const * p) 20320253Sjoerg{ 20420253Sjoerg char *q = NULL; 20520253Sjoerg 20620253Sjoerg if ((p = unquote(p)) != NULL) { 20720253Sjoerg int l = strlen(p) + 1; 20820253Sjoerg 20920253Sjoerg if ((q = malloc(l)) != NULL) 21020253Sjoerg memcpy(q, p, l); 21120253Sjoerg } 21220253Sjoerg return q; 21320253Sjoerg} 21420253Sjoerg 21520253Sjoerg 21620253Sjoergstruct userconf * 21720253Sjoergread_userconfig(char const * file) 21820253Sjoerg{ 21920253Sjoerg FILE *fp; 22020253Sjoerg 22120253Sjoerg if (file == NULL) 22220253Sjoerg file = _PATH_PW_CONF; 22320253Sjoerg if ((fp = fopen(file, "r")) != NULL) { 22420253Sjoerg char buf[_UC_MAXLINE]; 22520253Sjoerg 22620253Sjoerg while (fgets(buf, sizeof buf, fp) != NULL) { 22720253Sjoerg char *p = strchr(buf, '\n'); 22820253Sjoerg 22920253Sjoerg if (p == NULL) { /* Line too long */ 23020253Sjoerg int ch; 23120253Sjoerg 23220253Sjoerg while ((ch = fgetc(fp)) != '\n' && ch != EOF); 23320253Sjoerg } else { 23420253Sjoerg *p = '\0'; 23520253Sjoerg if (*buf && *buf != '\n' && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 23620253Sjoerg static char const toks[] = " \t\r\n,="; 23720253Sjoerg char *q = strtok(NULL, toks); 23820253Sjoerg int i = 0; 23920253Sjoerg 24020253Sjoerg while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 24120253Sjoerg ++i; 24220253Sjoerg#if debugging 24320253Sjoerg if (i == _UC_FIELDS) 24420253Sjoerg printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 24520253Sjoerg else 24620253Sjoerg printf("Got kwd[%s]=%s\n", p, q); 24720253Sjoerg#endif 24820253Sjoerg switch (i) { 24920253Sjoerg case _UC_DEFAULTPWD: 25020253Sjoerg config.default_password = boolean_val(q, 1); 25120253Sjoerg break; 25220253Sjoerg case _UC_REUSEUID: 25320253Sjoerg config.reuse_uids = boolean_val(q, 0); 25420253Sjoerg break; 25520253Sjoerg case _UC_REUSEGID: 25620253Sjoerg config.reuse_gids = boolean_val(q, 0); 25720253Sjoerg break; 25820253Sjoerg case _UC_DOTDIR: 25920253Sjoerg config.dotdir = (q == NULL || !boolean_val(q, 1)) 26020253Sjoerg ? NULL : newstr(q); 26120253Sjoerg break; 26220253Sjoerg case _UC_NEWMAIL: 26320253Sjoerg config.newmail = (q == NULL || !boolean_val(q, 1)) 26420253Sjoerg ? NULL : newstr(q); 26520253Sjoerg break; 26620253Sjoerg case _UC_LOGFILE: 26720253Sjoerg config.logfile = (q == NULL || !boolean_val(q, 1)) 26820253Sjoerg ? NULL : newstr(q); 26920253Sjoerg break; 27020253Sjoerg case _UC_HOMEROOT: 27120253Sjoerg config.home = (q == NULL || !boolean_val(q, 1)) 27220253Sjoerg ? "/home" : newstr(q); 27320253Sjoerg break; 27420253Sjoerg case _UC_SHELLPATH: 27520253Sjoerg config.shelldir = (q == NULL || !boolean_val(q, 1)) 27620253Sjoerg ? "/bin" : newstr(q); 27720253Sjoerg break; 27820253Sjoerg case _UC_SHELLS: 27920253Sjoerg for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 28020253Sjoerg system_shells[i] = newstr(q); 28120253Sjoerg if (i > 0) 28220253Sjoerg while (i < _UC_MAXSHELLS) 28320253Sjoerg system_shells[i++] = NULL; 28420253Sjoerg break; 28520253Sjoerg case _UC_DEFAULTSHELL: 28620253Sjoerg config.shell_default = (q == NULL || !boolean_val(q, 1)) 28720253Sjoerg ? (char *) bourne_shell : newstr(q); 28820253Sjoerg break; 28920253Sjoerg case _UC_DEFAULTGROUP: 29020253Sjoerg config.default_group = (q == NULL || !boolean_val(q, 1) || getgrnam(q) == NULL) 29120253Sjoerg ? NULL : newstr(q); 29220253Sjoerg break; 29320253Sjoerg case _UC_EXTRAGROUPS: 29420253Sjoerg for (i = 0; i < _UC_MAXGROUPS && q != NULL; i++, q = strtok(NULL, toks)) 29520253Sjoerg default_groups[i] = newstr(q); 29620253Sjoerg if (i > 0) 29720253Sjoerg while (i < _UC_MAXGROUPS) 29820253Sjoerg default_groups[i++] = NULL; 29920253Sjoerg break; 30020253Sjoerg case _UC_DEFAULTCLASS: 30120253Sjoerg config.default_class = (q == NULL || !boolean_val(q, 1)) 30220253Sjoerg ? NULL : newstr(q); 30320253Sjoerg break; 30420253Sjoerg case _UC_MINUID: 30520253Sjoerg if ((q = unquote(q)) != NULL && isdigit(*q)) 30620253Sjoerg config.min_uid = (uid_t) atol(q); 30720253Sjoerg break; 30820253Sjoerg case _UC_MAXUID: 30920253Sjoerg if ((q = unquote(q)) != NULL && isdigit(*q)) 31020253Sjoerg config.max_uid = (uid_t) atol(q); 31120253Sjoerg break; 31220253Sjoerg case _UC_MINGID: 31320253Sjoerg if ((q = unquote(q)) != NULL && isdigit(*q)) 31420253Sjoerg config.min_gid = (gid_t) atol(q); 31520253Sjoerg break; 31620253Sjoerg case _UC_MAXGID: 31720253Sjoerg if ((q = unquote(q)) != NULL && isdigit(*q)) 31820253Sjoerg config.max_gid = (gid_t) atol(q); 31920253Sjoerg break; 32020253Sjoerg case _UC_EXPIRE: 32120253Sjoerg if ((q = unquote(q)) != NULL && isdigit(*q)) 32220253Sjoerg config.expire_days = atoi(q); 32320253Sjoerg break; 32420253Sjoerg case _UC_PASSWORD: 32520253Sjoerg if ((q = unquote(q)) != NULL && isdigit(*q)) 32620253Sjoerg config.password_days = atoi(q); 32720253Sjoerg break; 32820253Sjoerg case _UC_FIELDS: 32920253Sjoerg case _UC_NONE: 33020253Sjoerg break; 33120253Sjoerg } 33220253Sjoerg } 33320253Sjoerg } 33420253Sjoerg } 33520253Sjoerg fclose(fp); 33620253Sjoerg } 33720253Sjoerg return &config; 33820253Sjoerg} 33920253Sjoerg 34020253Sjoerg 34120253Sjoergint 34220253Sjoergwrite_userconfig(char const * file) 34320253Sjoerg{ 34420253Sjoerg int fd; 34520253Sjoerg 34620253Sjoerg if (file == NULL) 34720253Sjoerg file = _PATH_PW_CONF; 34820253Sjoerg 34920253Sjoerg if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { 35020253Sjoerg FILE *fp; 35120253Sjoerg 35220253Sjoerg if ((fp = fdopen(fd, "w")) == NULL) 35320253Sjoerg close(fd); 35420253Sjoerg else { 35520253Sjoerg int i, j, k; 35620253Sjoerg char buf[_UC_MAXLINE]; 35720253Sjoerg 35820253Sjoerg for (i = _UC_NONE; i < _UC_FIELDS; i++) { 35920253Sjoerg int quote = 1; 36020253Sjoerg char const *val = buf; 36120253Sjoerg 36220253Sjoerg *buf = '\0'; 36320253Sjoerg switch (i) { 36420253Sjoerg case _UC_DEFAULTPWD: 36520253Sjoerg val = boolean_str(config.default_password); 36620253Sjoerg break; 36720253Sjoerg case _UC_REUSEUID: 36820253Sjoerg val = boolean_str(config.reuse_uids); 36920253Sjoerg break; 37020253Sjoerg case _UC_REUSEGID: 37120253Sjoerg val = boolean_str(config.reuse_gids); 37220253Sjoerg break; 37320253Sjoerg case _UC_DOTDIR: 37420253Sjoerg val = config.dotdir ? config.dotdir : boolean_str(0); 37520253Sjoerg break; 37620253Sjoerg case _UC_NEWMAIL: 37720253Sjoerg val = config.newmail ? config.newmail : boolean_str(0); 37820253Sjoerg break; 37920253Sjoerg case _UC_LOGFILE: 38020253Sjoerg val = config.logfile ? config.logfile : boolean_str(0); 38120253Sjoerg break; 38220253Sjoerg case _UC_HOMEROOT: 38320253Sjoerg val = config.home; 38420253Sjoerg break; 38520253Sjoerg case _UC_SHELLPATH: 38620253Sjoerg val = config.shelldir; 38720253Sjoerg break; 38820253Sjoerg case _UC_SHELLS: 38920253Sjoerg for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) 39020253Sjoerg k += sprintf(buf + k, "%s\"%s\"", k ? "," : "", system_shells[j]); 39120253Sjoerg quote = 0; 39220253Sjoerg break; 39320253Sjoerg case _UC_DEFAULTSHELL: 39420253Sjoerg val = config.shell_default ? config.shell_default : bourne_shell; 39520253Sjoerg break; 39620253Sjoerg case _UC_DEFAULTGROUP: 39720253Sjoerg val = config.default_group ? config.default_group : ""; 39820253Sjoerg break; 39920253Sjoerg case _UC_EXTRAGROUPS: 40020253Sjoerg for (j = k = 0; j < _UC_MAXGROUPS && default_groups[j] != NULL; j++) 40120253Sjoerg k += sprintf(buf + k, "%s\"%s\"", k ? "," : "", default_groups[j]); 40220253Sjoerg quote = 0; 40320253Sjoerg break; 40420253Sjoerg case _UC_DEFAULTCLASS: 40520253Sjoerg val = config.default_class ? config.default_class : ""; 40620253Sjoerg break; 40720253Sjoerg case _UC_MINUID: 40820253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_uid); 40920253Sjoerg quote = 0; 41020253Sjoerg break; 41120253Sjoerg case _UC_MAXUID: 41220253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_uid); 41320253Sjoerg quote = 0; 41420253Sjoerg break; 41520253Sjoerg case _UC_MINGID: 41620253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_gid); 41720253Sjoerg quote = 0; 41820253Sjoerg break; 41920253Sjoerg case _UC_MAXGID: 42020253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_gid); 42120253Sjoerg quote = 0; 42220253Sjoerg break; 42320253Sjoerg case _UC_EXPIRE: 42420253Sjoerg sprintf(buf, "%d", config.expire_days); 42520253Sjoerg quote = 0; 42620253Sjoerg break; 42720253Sjoerg case _UC_PASSWORD: 42820253Sjoerg sprintf(buf, "%d", config.password_days); 42920253Sjoerg quote = 0; 43020253Sjoerg break; 43120253Sjoerg case _UC_NONE: 43220253Sjoerg break; 43320253Sjoerg } 43420253Sjoerg 43520253Sjoerg if (comments[i]) 43620253Sjoerg fputs(comments[i], fp); 43720253Sjoerg 43820253Sjoerg if (*kwds[i]) { 43920253Sjoerg if (quote) 44020253Sjoerg fprintf(fp, "%s = \"%s\"\n", kwds[i], val); 44120253Sjoerg else 44220253Sjoerg fprintf(fp, "%s = %s\n", kwds[i], val); 44320253Sjoerg#if debugging 44420253Sjoerg printf("WROTE: %s = %s\n", kwds[i], val); 44520253Sjoerg#endif 44620253Sjoerg } 44720253Sjoerg } 44820253Sjoerg return fclose(fp) != EOF; 44920253Sjoerg } 45020253Sjoerg } 45120253Sjoerg return 0; 45220253Sjoerg} 453