1 /* password.c - password read/update helper functions.
3 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
11 // generate appropriate random salt string for given encryption algorithm.
12 int get_salt(char *salt, char *algo)
16 } al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}};
19 for (i = 0; i < ARRAY_LEN(al); i++) {
20 if (!strcmp(algo, al[i].type)) {
24 if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
26 // Read appropriate number of random bytes for salt
27 i = xopenro("/dev/urandom");
28 xreadall(i, libbuf, ((len*6)+7)/8);
31 // 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;
35 bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
37 if (bits > 57) bits += 7;
38 if (bits > 90) bits += 6;
51 // Prompt with mesg, read password into buf, return 0 for success 1 for fail
52 int read_password(char *buf, int buflen, char *mesg)
54 struct termios oldtermio;
55 struct sigaction sa, oldsa;
58 // NOP signal handler to return from the read
59 memset(&sa, 0, sizeof(sa));
60 sa.sa_handler = generic_signal;
61 sigaction(SIGINT, &sa, &oldsa);
64 set_terminal(0, 1, &oldtermio);
68 for (i=0; i < buflen-1; i++) {
69 if ((ret = read(0, buf+i, 1)) < 0 || (!ret && !i)) {
74 } else if (!ret || buf[i] == '\n' || buf[i] == '\r') {
78 } else if (buf[i] == 8 || buf[i] == 127) i -= i ? 2 : 1;
81 // Restore terminal/signal state, terminate string
82 sigaction(SIGINT, &oldsa, NULL);
83 tcsetattr(0, TCSANOW, &oldtermio);
90 static char *get_nextcolon(char *line, int cnt)
93 if (!(line = strchr(line, ':'))) error_exit("Invalid Entry\n");
94 line++; //jump past the colon
99 /*update_password is used by multiple utilities to update /etc/passwd,
100 * /etc/shadow, /etc/group and /etc/gshadow files,
101 * which are used as user, group databeses
103 * 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
107 * 5. entry = NULL, delete the named entry user/group
109 int update_password(char *filename, char* username, char* entry)
111 char *filenamesfx = NULL, *namesfx = NULL, *shadow = NULL,
112 *sfx = NULL, *line = NULL;
114 int ret = -1, found = 0;
117 shadow = strstr(filename, "shadow");
118 filenamesfx = xmprintf("%s+", filename);
119 sfx = strchr(filenamesfx, '+');
121 exfp = fopen(filename, "r+");
123 perror_msg("Couldn't open file %s",filename);
129 ret = link(filename, filenamesfx);
130 if (ret < 0) error_msg("can't create backup file");
133 lock.l_type = F_WRLCK;
134 lock.l_whence = SEEK_SET;
138 ret = fcntl(fileno(exfp), F_SETLK, &lock);
139 if (ret < 0) perror_msg("Couldn't lock file %s",filename);
141 lock.l_type = F_UNLCK; //unlocking at a later stage
143 newfp = fopen(filenamesfx, "w+");
145 error_msg("couldn't open file for writing");
152 namesfx = xmprintf("%s:",username);
153 while ((line = get_line(fileno(exfp))) != NULL)
155 if (strncmp(line, namesfx, strlen(namesfx)))
156 fprintf(newfp, "%s\n", line);
158 char *current_ptr = NULL;
161 if (!strcmp(toys.which->name, "passwd")) {
162 fprintf(newfp, "%s%s:",namesfx, entry);
163 current_ptr = get_nextcolon(line, 2); //past passwd
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);
169 } else if (!strcmp(toys.which->name, "groupadd") ||
170 !strcmp(toys.which->name, "addgroup") ||
171 !strcmp(toys.which->name, "delgroup") ||
172 !strcmp(toys.which->name, "groupdel")){
173 current_ptr = get_nextcolon(line, 3); //past gid/admin list
175 fprintf(newfp, "%s", line);
176 fprintf(newfp, "%s\n", entry);
182 if (!found && entry) fprintf(newfp, "%s\n", entry);
183 fcntl(fileno(exfp), F_SETLK, &lock);
188 fsync(fileno(newfp));
190 rename(filenamesfx, filename);
192 perror_msg("File Writing/Saving failed: ");