--- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1019,7 +1019,7 @@ TEST_LP_LOAD_OBJ = param/test_lp_load.o PASSWD_UTIL_OBJ = utils/passwd_util.o -SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \ +SMBPASSWD_OBJ = utils/owrt_smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \ $(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) \ $(GROUPDB_OBJ) $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \ $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) \ @@ -1791,7 +1791,7 @@ nmbd/nmbd_multicall.o: nmbd/nmbd.c nmbd/ echo "$(COMPILE_CC_PATH)" 1>&2;\ $(COMPILE_CC_PATH) >/dev/null 2>&1 -utils/smbpasswd_multicall.o: utils/smbpasswd.c utils/smbpasswd.o +utils/smbpasswd_multicall.o: utils/owrt_smbpasswd.c utils/owrt_smbpasswd.o @echo Compiling $<.c @$(COMPILE_CC_PATH) -Dmain=smbpasswd_main && exit 0;\ echo "The following command failed:" 1>&2;\ @@ -1800,7 +1800,7 @@ utils/smbpasswd_multicall.o: utils/smbpa SMBD_MULTI_O = $(patsubst smbd/server.o,smbd/server_multicall.o,$(SMBD_OBJ)) NMBD_MULTI_O = $(patsubst nmbd/nmbd.o,nmbd/nmbd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(NMBD_OBJ))) -SMBPASSWD_MULTI_O = $(patsubst utils/smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ))) +SMBPASSWD_MULTI_O = $(patsubst utils/owrt_smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ))) MULTI_O = multi.o MULTICALL_O = $(sort $(SMBD_MULTI_O) $(NMBD_MULTI_O) $(SMBPASSWD_MULTI_O) $(MULTI_O)) --- /dev/null +++ b/source3/utils/owrt_smbpasswd.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2012 Felix Fietkau + * Copyright (C) 2008 John Crispin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include +#include + +static char buf[256]; + +static void md4hash(const char *passwd, uchar p16[16]) +{ + int len; + smb_ucs2_t wpwd[129]; + int i; + + len = strlen(passwd); + for (i = 0; i < len; i++) { +#if __BYTE_ORDER == __LITTLE_ENDIAN + wpwd[i] = (unsigned char)passwd[i]; +#else + wpwd[i] = (unsigned char)passwd[i] << 8; +#endif + } + wpwd[i] = 0; + + len = len * sizeof(int16); + mdfour(p16, (unsigned char *)wpwd, len); + ZERO_STRUCT(wpwd); +} + + +static bool find_passwd_line(FILE *fp, const char *user, char **next) +{ + char *p1; + + while (!feof(fp)) { + if(!fgets(buf, sizeof(buf) - 1, fp)) + continue; + + p1 = strchr(buf, ':'); + + if (p1 - buf != strlen(user)) + continue; + + if (strncmp(buf, user, p1 - buf) != 0) + continue; + + if (next) + *next = p1; + return true; + } + return false; +} + +/* returns -1 if user is not present in /etc/passwd*/ +static int find_uid_for_user(const char *user) +{ + FILE *fp; + char *p1, *p2, *p3; + int ret = -1; + + fp = fopen("/etc/passwd", "r"); + if (!fp) { + printf("failed to open /etc/passwd"); + goto out; + } + + if (!find_passwd_line(fp, user, &p1)) { + printf("User %s not found or invalid in /etc/passwd\n", user); + goto out; + } + + p2 = strchr(p1 + 1, ':'); + if (!p2) + goto out; + + p2++; + p3 = strchr(p2, ':'); + if (!p1) + goto out; + + *p3 = '\0'; + ret = atoi(p2); + +out: + if(fp) + fclose(fp); + return ret; +} + +static void smbpasswd_write_user(FILE *fp, const char *user, int uid, const char *password) +{ + static uchar nt_p16[NT_HASH_LEN]; + int len = 0; + int i; + + md4hash(strdup(password), nt_p16); + + len += snprintf(buf + len, sizeof(buf) - len, "%s:%u:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:", user, uid); + for(i = 0; i < NT_HASH_LEN; i++) + len += snprintf(buf + len, sizeof(buf) - len, "%02X", nt_p16[i]); + + snprintf(buf + len, sizeof(buf) - len, ":[U ]:LCT-00000001:\n"); + fputs(buf, fp); +} + +static void smbpasswd_delete_user(FILE *fp) +{ + fpos_t r_pos, w_pos; + int len = strlen(buf); + + fgetpos(fp, &r_pos); + fseek(fp, -len, SEEK_CUR); + fgetpos(fp, &w_pos); + fsetpos(fp, &r_pos); + + while (fgets(buf, sizeof(buf) - 1, fp)) { + int cur_len = strlen(buf); + + fsetpos(fp, &w_pos); + fputs(buf, fp); + fgetpos(fp, &w_pos); + + fsetpos(fp, &r_pos); + fseek(fp, cur_len, SEEK_CUR); + fgetpos(fp, &r_pos); + } + + fsetpos(fp, &w_pos); + ftruncate(fileno(fp), ftello(fp)); +} + +static int usage(const char *progname) +{ + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " -s read password from stdin\n" + " -a add user\n" + " -x delete user\n", + progname); + return 1; +} + +int main(int argc, char **argv) +{ + const char *prog = argv[0]; + const char *user; + char *pw1, *pw2; + FILE *fp; + bool add = false, delete = false, get_stdin = false, found; + int ch; + int uid; + + TALLOC_CTX *frame = talloc_stackframe(); + + while ((ch = getopt(argc, argv, "asx")) != EOF) { + switch (ch) { + case 's': + get_stdin = true; + break; + case 'a': + add = true; + break; + case 'x': + delete = true; + break; + default: + return usage(prog); + } + } + + if (add && delete) + return usage(prog); + + argc -= optind; + argv += optind; + + if (!argc) + return usage(prog); + + user = argv[0]; + if (!delete) { + uid = find_uid_for_user(user); + if (uid < 0) { + fprintf(stderr, "Could not find user '%s' in /etc/passwd\n", user); + return 2; + } + } + + fp = fopen("/etc/samba/smbpasswd", "r+"); + if(!fp) { + fprintf(stderr, "Failed to open /etc/samba/smbpasswd"); + return 3; + } + + found = find_passwd_line(fp, user, NULL); + if (!add && !found) { + fprintf(stderr, "Could not find user '%s' in /etc/samba/smbpasswd\n", user); + return 3; + } + + if (delete) { + smbpasswd_delete_user(fp); + goto out; + } + + pw1 = get_pass("New SMB password:", get_stdin); + if (!pw1) + pw1 = strdup(""); + + pw2 = get_pass("Retype SMB password:", get_stdin); + if (!pw2) + pw2 = strdup(""); + + if (strcmp(pw1, pw2) != 0) { + fprintf(stderr, "Mismatch - password unchanged.\n"); + goto out_free; + } + + if (found) + fseek(fp, -strlen(buf), SEEK_CUR); + smbpasswd_write_user(fp, user, uid, pw2); + +out_free: + free(pw1); + free(pw2); +out: + fclose(fp); + TALLOC_FREE(frame); + + return 0; +}