blob: eab2d669dc7f16f91ccfe3865339e358bc14f48e [file] [log] [blame]
Rob Landleyd0f79352013-10-16 19:30:17 -05001/* password.c - password read/update helper functions.
Rob Landley2c917f52012-07-17 08:54:47 -05002 *
3 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
Rob Landleyf033f862015-05-31 05:11:28 -05004 *
5 * TODO: cleanup
Rob Landley2c917f52012-07-17 08:54:47 -05006 */
7
8#include "toys.h"
9#include <time.h>
10
Rob Landley6d15f0d2014-06-25 22:54:59 -050011// generate appropriate random salt string for given encryption algorithm.
Rob Landleyd0f79352013-10-16 19:30:17 -050012int get_salt(char *salt, char *algo)
Rob Landley2c1cf4a2015-01-18 14:06:14 -060013{
Rob Landley6d15f0d2014-06-25 22:54:59 -050014 struct {
15 char *type, id, len;
16 } al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}};
17 int i;
Rob Landleyd0f79352013-10-16 19:30:17 -050018
Rob Landley6d15f0d2014-06-25 22:54:59 -050019 for (i = 0; i < ARRAY_LEN(al); i++) {
20 if (!strcmp(algo, al[i].type)) {
21 int len = al[i].len;
22 char *s = salt;
Rob Landleyd0f79352013-10-16 19:30:17 -050023
Rob Landleye0d80092014-09-26 18:49:44 -050024 if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
Rob Landleyd0f79352013-10-16 19:30:17 -050025
Rob Landley6d15f0d2014-06-25 22:54:59 -050026 // Read appropriate number of random bytes for salt
Rob Landley027a73a2016-08-04 10:16:59 -050027 i = xopenro("/dev/urandom");
Rob Landley6d15f0d2014-06-25 22:54:59 -050028 xreadall(i, libbuf, ((len*6)+7)/8);
29 close(i);
Rob Landley34037422013-10-16 20:01:46 -050030
Rob Landley6d15f0d2014-06-25 22:54:59 -050031 // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
32 for (i=0; i<len; i++) {
33 int bitpos = i*6, bits = bitpos/8;
Rob Landley34037422013-10-16 20:01:46 -050034
Rob Landley6d15f0d2014-06-25 22:54:59 -050035 bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
36 bits += 46;
37 if (bits > 57) bits += 7;
38 if (bits > 90) bits += 6;
Rob Landley34037422013-10-16 20:01:46 -050039
Rob Landley6d15f0d2014-06-25 22:54:59 -050040 s[i] = bits;
41 }
42 salt[len] = 0;
43
44 return s-salt;
45 }
Rob Landley34037422013-10-16 20:01:46 -050046 }
Rob Landleyd0f79352013-10-16 19:30:17 -050047
Rob Landley6d15f0d2014-06-25 22:54:59 -050048 return -1;
Rob Landleyd0f79352013-10-16 19:30:17 -050049}
50
Rob Landleyc0e5ff32014-06-28 20:02:01 -050051// Prompt with mesg, read password into buf, return 0 for success 1 for fail
52int read_password(char *buf, int buflen, char *mesg)
Rob Landley7aa651a2012-11-13 17:14:08 -060053{
Rob Landleyc0e5ff32014-06-28 20:02:01 -050054 struct termios oldtermio;
Rob Landleyd0f79352013-10-16 19:30:17 -050055 struct sigaction sa, oldsa;
Rob Landleyc0e5ff32014-06-28 20:02:01 -050056 int i, ret = 1;
Rob Landleyd0f79352013-10-16 19:30:17 -050057
Rob Landleyc0e5ff32014-06-28 20:02:01 -050058 // NOP signal handler to return from the read
Rob Landleyd0f79352013-10-16 19:30:17 -050059 memset(&sa, 0, sizeof(sa));
Rob Landleyc0e5ff32014-06-28 20:02:01 -050060 sa.sa_handler = generic_signal;
Rob Landleyd0f79352013-10-16 19:30:17 -050061 sigaction(SIGINT, &sa, &oldsa);
62
Rob Landleyc0e5ff32014-06-28 20:02:01 -050063 tcflush(0, TCIFLUSH);
64 set_terminal(0, 1, &oldtermio);
Rob Landley2c917f52012-07-17 08:54:47 -050065
Rob Landleyc0e5ff32014-06-28 20:02:01 -050066 xprintf("%s", mesg);
Rob Landley2c917f52012-07-17 08:54:47 -050067
Rob Landleyc0e5ff32014-06-28 20:02:01 -050068 for (i=0; i < buflen-1; i++) {
69 if ((ret = read(0, buf+i, 1)) < 0 || (!ret && !i)) {
70 i = 0;
71 ret = 1;
72
Rob Landley7aa651a2012-11-13 17:14:08 -060073 break;
Rob Landleyc0e5ff32014-06-28 20:02:01 -050074 } else if (!ret || buf[i] == '\n' || buf[i] == '\r') {
75 ret = 0;
76
77 break;
78 } else if (buf[i] == 8 || buf[i] == 127) i -= i ? 2 : 1;
Rob Landley7aa651a2012-11-13 17:14:08 -060079 }
Rob Landleyc0e5ff32014-06-28 20:02:01 -050080
81 // Restore terminal/signal state, terminate string
Rob Landleyd0f79352013-10-16 19:30:17 -050082 sigaction(SIGINT, &oldsa, NULL);
Rob Landley7aa651a2012-11-13 17:14:08 -060083 tcsetattr(0, TCSANOW, &oldtermio);
Rob Landleyc0e5ff32014-06-28 20:02:01 -050084 buf[i] = 0;
85 xputc('\n');
86
87 return ret;
Rob Landley2c917f52012-07-17 08:54:47 -050088}
89
Rob Landleyd0f79352013-10-16 19:30:17 -050090static char *get_nextcolon(char *line, int cnt)
Rob Landley2c917f52012-07-17 08:54:47 -050091{
Rob Landleyd0f79352013-10-16 19:30:17 -050092 while (cnt--) {
93 if (!(line = strchr(line, ':'))) error_exit("Invalid Entry\n");
94 line++; //jump past the colon
95 }
96 return line;
Rob Landley2c917f52012-07-17 08:54:47 -050097}
98
Rob Landleyd0f79352013-10-16 19:30:17 -050099/*update_password is used by multiple utilities to update /etc/passwd,
Rob Landley2c1cf4a2015-01-18 14:06:14 -0600100 * /etc/shadow, /etc/group and /etc/gshadow files,
Rob Landleyd0f79352013-10-16 19:30:17 -0500101 * which are used as user, group databeses
Rob Landley2c1cf4a2015-01-18 14:06:14 -0600102 * entry can be
Rob Landleyd0f79352013-10-16 19:30:17 -0500103 * 1. encrypted password, when updating user password.
104 * 2. complete entry for user details, when creating new user
105 * 3. group members comma',' separated list, when adding user to group
106 * 4. complete entry for group details, when creating new group
Ashwini Sharma656d5042013-12-23 07:23:28 -0600107 * 5. entry = NULL, delete the named entry user/group
Rob Landleyd0f79352013-10-16 19:30:17 -0500108 */
109int update_password(char *filename, char* username, char* entry)
Rob Landley2c917f52012-07-17 08:54:47 -0500110{
Rob Landleyd0f79352013-10-16 19:30:17 -0500111 char *filenamesfx = NULL, *namesfx = NULL, *shadow = NULL,
112 *sfx = NULL, *line = NULL;
Rob Landley7aa651a2012-11-13 17:14:08 -0600113 FILE *exfp, *newfp;
Rob Landleyd0f79352013-10-16 19:30:17 -0500114 int ret = -1, found = 0;
Rob Landley7aa651a2012-11-13 17:14:08 -0600115 struct flock lock;
Rob Landley2c917f52012-07-17 08:54:47 -0500116
Rob Landley7aa651a2012-11-13 17:14:08 -0600117 shadow = strstr(filename, "shadow");
Rob Landley59d85e22014-01-16 09:26:50 -0600118 filenamesfx = xmprintf("%s+", filename);
Rob Landley7aa651a2012-11-13 17:14:08 -0600119 sfx = strchr(filenamesfx, '+');
Rob Landley2c917f52012-07-17 08:54:47 -0500120
Rob Landley7aa651a2012-11-13 17:14:08 -0600121 exfp = fopen(filename, "r+");
Rob Landleyd0f79352013-10-16 19:30:17 -0500122 if (!exfp) {
Rob Landley7aa651a2012-11-13 17:14:08 -0600123 perror_msg("Couldn't open file %s",filename);
124 goto free_storage;
125 }
Rob Landley2c917f52012-07-17 08:54:47 -0500126
Rob Landley7aa651a2012-11-13 17:14:08 -0600127 *sfx = '-';
Rob Landley6e087a32014-11-11 15:08:25 -0600128 unlink(filenamesfx);
Rob Landley7aa651a2012-11-13 17:14:08 -0600129 ret = link(filename, filenamesfx);
Rob Landleyd0f79352013-10-16 19:30:17 -0500130 if (ret < 0) error_msg("can't create backup file");
Rob Landley2c917f52012-07-17 08:54:47 -0500131
Rob Landley7aa651a2012-11-13 17:14:08 -0600132 *sfx = '+';
133 lock.l_type = F_WRLCK;
134 lock.l_whence = SEEK_SET;
135 lock.l_start = 0;
136 lock.l_len = 0;
Rob Landley2c917f52012-07-17 08:54:47 -0500137
Rob Landley7aa651a2012-11-13 17:14:08 -0600138 ret = fcntl(fileno(exfp), F_SETLK, &lock);
Rob Landleyd0f79352013-10-16 19:30:17 -0500139 if (ret < 0) perror_msg("Couldn't lock file %s",filename);
Rob Landley2c917f52012-07-17 08:54:47 -0500140
Rob Landley7aa651a2012-11-13 17:14:08 -0600141 lock.l_type = F_UNLCK; //unlocking at a later stage
Rob Landley2c917f52012-07-17 08:54:47 -0500142
Rob Landley7aa651a2012-11-13 17:14:08 -0600143 newfp = fopen(filenamesfx, "w+");
Rob Landleyd0f79352013-10-16 19:30:17 -0500144 if (!newfp) {
Rob Landley7aa651a2012-11-13 17:14:08 -0600145 error_msg("couldn't open file for writing");
146 ret = -1;
Rob Landley2c917f52012-07-17 08:54:47 -0500147 fclose(exfp);
Rob Landley7aa651a2012-11-13 17:14:08 -0600148 goto free_storage;
149 }
150
151 ret = 0;
Rob Landley59d85e22014-01-16 09:26:50 -0600152 namesfx = xmprintf("%s:",username);
Rob Landleyd0f79352013-10-16 19:30:17 -0500153 while ((line = get_line(fileno(exfp))) != NULL)
Rob Landley7aa651a2012-11-13 17:14:08 -0600154 {
Rob Landleyd0f79352013-10-16 19:30:17 -0500155 if (strncmp(line, namesfx, strlen(namesfx)))
Rob Landley7aa651a2012-11-13 17:14:08 -0600156 fprintf(newfp, "%s\n", line);
Ashwini Sharma656d5042013-12-23 07:23:28 -0600157 else if (entry) {
Rob Landley7aa651a2012-11-13 17:14:08 -0600158 char *current_ptr = NULL;
Rob Landley7aa651a2012-11-13 17:14:08 -0600159
Rob Landleyd0f79352013-10-16 19:30:17 -0500160 found = 1;
161 if (!strcmp(toys.which->name, "passwd")) {
162 fprintf(newfp, "%s%s:",namesfx, entry);
163 current_ptr = get_nextcolon(line, 2); //past passwd
164 if (shadow) {
165 fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60));
166 current_ptr = get_nextcolon(current_ptr, 1);
167 fprintf(newfp, "%s\n",current_ptr);
168 } else fprintf(newfp, "%s\n",current_ptr);
Rob Landley2c1cf4a2015-01-18 14:06:14 -0600169 } else if (!strcmp(toys.which->name, "groupadd") ||
Ashwini Sharma656d5042013-12-23 07:23:28 -0600170 !strcmp(toys.which->name, "addgroup") ||
171 !strcmp(toys.which->name, "delgroup") ||
172 !strcmp(toys.which->name, "groupdel")){
Rob Landleyd0f79352013-10-16 19:30:17 -0500173 current_ptr = get_nextcolon(line, 3); //past gid/admin list
174 *current_ptr = '\0';
175 fprintf(newfp, "%s", line);
176 fprintf(newfp, "%s\n", entry);
177 }
178 }
Rob Landley7aa651a2012-11-13 17:14:08 -0600179 free(line);
180 }
181 free(namesfx);
Ashwini Sharma656d5042013-12-23 07:23:28 -0600182 if (!found && entry) fprintf(newfp, "%s\n", entry);
Rob Landley7aa651a2012-11-13 17:14:08 -0600183 fcntl(fileno(exfp), F_SETLK, &lock);
184 fclose(exfp);
185
186 errno = 0;
187 fflush(newfp);
188 fsync(fileno(newfp));
189 fclose(newfp);
190 rename(filenamesfx, filename);
Rob Landleyd0f79352013-10-16 19:30:17 -0500191 if (errno) {
Rob Landley7aa651a2012-11-13 17:14:08 -0600192 perror_msg("File Writing/Saving failed: ");
193 unlink(filenamesfx);
194 ret = -1;
195 }
Rob Landley2c917f52012-07-17 08:54:47 -0500196
197free_storage:
Rob Landley7aa651a2012-11-13 17:14:08 -0600198 free(filenamesfx);
199 return ret;
200}