1--- a/source3/Makefile.in 2+++ b/source3/Makefile.in 3@@ -1025,7 +1025,7 @@ TEST_LP_LOAD_OBJ = param/test_lp_load.o 4 5 PASSWD_UTIL_OBJ = utils/passwd_util.o 6 7-SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \ 8+SMBPASSWD_OBJ = utils/owrt_smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \ 9 $(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) \ 10 $(GROUPDB_OBJ) $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \ 11 $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) \ 12@@ -1813,7 +1813,7 @@ nmbd/nmbd_multicall.o: nmbd/nmbd.c nmbd/ 13 echo "$(COMPILE_CC_PATH)" 1>&2;\ 14 $(COMPILE_CC_PATH) >/dev/null 2>&1 15 16-utils/smbpasswd_multicall.o: utils/smbpasswd.c utils/smbpasswd.o 17+utils/smbpasswd_multicall.o: utils/owrt_smbpasswd.c utils/owrt_smbpasswd.o 18 @echo Compiling $<.c 19 @$(COMPILE_CC_PATH) -Dmain=smbpasswd_main && exit 0;\ 20 echo "The following command failed:" 1>&2;\ 21@@ -1822,7 +1822,7 @@ utils/smbpasswd_multicall.o: utils/smbpa 22 23 SMBD_MULTI_O = $(patsubst smbd/server.o,smbd/server_multicall.o,$(SMBD_OBJ)) 24 NMBD_MULTI_O = $(patsubst nmbd/nmbd.o,nmbd/nmbd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(NMBD_OBJ))) 25-SMBPASSWD_MULTI_O = $(patsubst utils/smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ))) 26+SMBPASSWD_MULTI_O = $(patsubst utils/owrt_smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ))) 27 MULTI_O = multi.o 28 29 MULTICALL_O = $(sort $(SMBD_MULTI_O) $(NMBD_MULTI_O) $(SMBPASSWD_MULTI_O) $(MULTI_O)) 30--- /dev/null 31+++ b/source3/utils/owrt_smbpasswd.c 32@@ -0,0 +1,249 @@ 33+/* 34+ * Copyright (C) 2012 Felix Fietkau <nbd@nbd.name> 35+ * Copyright (C) 2008 John Crispin <blogic@openwrt.org> 36+ * 37+ * This program is free software; you can redistribute it and/or modify it 38+ * under the terms of the GNU General Public License as published by the 39+ * Free Software Foundation; either version 2 of the License, or (at your 40+ * option) any later version. 41+ * 42+ * This program is distributed in the hope that it will be useful, but WITHOUT 43+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 44+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 45+ * more details. 46+ * 47+ * You should have received a copy of the GNU General Public License along with 48+ * this program; if not, write to the Free Software Foundation, Inc., 675 49+ * Mass Ave, Cambridge, MA 02139, USA. */ 50+ 51+#include "includes.h" 52+#include <endian.h> 53+#include <stdio.h> 54+ 55+static char buf[256]; 56+ 57+static void md4hash(const char *passwd, uchar p16[16]) 58+{ 59+ int len; 60+ smb_ucs2_t wpwd[129]; 61+ int i; 62+ 63+ len = strlen(passwd); 64+ for (i = 0; i < len; i++) { 65+#if __BYTE_ORDER == __LITTLE_ENDIAN 66+ wpwd[i] = (unsigned char)passwd[i]; 67+#else 68+ wpwd[i] = (unsigned char)passwd[i] << 8; 69+#endif 70+ } 71+ wpwd[i] = 0; 72+ 73+ len = len * sizeof(int16); 74+ mdfour(p16, (unsigned char *)wpwd, len); 75+ ZERO_STRUCT(wpwd); 76+} 77+ 78+ 79+static bool find_passwd_line(FILE *fp, const char *user, char **next) 80+{ 81+ char *p1; 82+ 83+ while (!feof(fp)) { 84+ if(!fgets(buf, sizeof(buf) - 1, fp)) 85+ continue; 86+ 87+ p1 = strchr(buf, ':'); 88+ 89+ if (p1 - buf != strlen(user)) 90+ continue; 91+ 92+ if (strncmp(buf, user, p1 - buf) != 0) 93+ continue; 94+ 95+ if (next) 96+ *next = p1; 97+ return true; 98+ } 99+ return false; 100+} 101+ 102+/* returns -1 if user is not present in /etc/passwd*/ 103+static int find_uid_for_user(const char *user) 104+{ 105+ FILE *fp; 106+ char *p1, *p2, *p3; 107+ int ret = -1; 108+ 109+ fp = fopen("/etc/passwd", "r"); 110+ if (!fp) { 111+ printf("failed to open /etc/passwd"); 112+ goto out; 113+ } 114+ 115+ if (!find_passwd_line(fp, user, &p1)) { 116+ printf("User %s not found or invalid in /etc/passwd\n", user); 117+ goto out; 118+ } 119+ 120+ p2 = strchr(p1 + 1, ':'); 121+ if (!p2) 122+ goto out; 123+ 124+ p2++; 125+ p3 = strchr(p2, ':'); 126+ if (!p1) 127+ goto out; 128+ 129+ *p3 = '\0'; 130+ ret = atoi(p2); 131+ 132+out: 133+ if(fp) 134+ fclose(fp); 135+ return ret; 136+} 137+ 138+static void smbpasswd_write_user(FILE *fp, const char *user, int uid, const char *password) 139+{ 140+ static uchar nt_p16[NT_HASH_LEN]; 141+ int len = 0; 142+ int i; 143+ 144+ md4hash(strdup(password), nt_p16); 145+ 146+ len += snprintf(buf + len, sizeof(buf) - len, "%s:%u:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:", user, uid); 147+ for(i = 0; i < NT_HASH_LEN; i++) 148+ len += snprintf(buf + len, sizeof(buf) - len, "%02X", nt_p16[i]); 149+ 150+ snprintf(buf + len, sizeof(buf) - len, ":[U ]:LCT-00000001:\n"); 151+ fputs(buf, fp); 152+} 153+ 154+static void smbpasswd_delete_user(FILE *fp) 155+{ 156+ fpos_t r_pos, w_pos; 157+ int len = strlen(buf); 158+ 159+ fgetpos(fp, &r_pos); 160+ fseek(fp, -len, SEEK_CUR); 161+ fgetpos(fp, &w_pos); 162+ fsetpos(fp, &r_pos); 163+ 164+ while (fgets(buf, sizeof(buf) - 1, fp)) { 165+ int cur_len = strlen(buf); 166+ 167+ fsetpos(fp, &w_pos); 168+ fputs(buf, fp); 169+ fgetpos(fp, &w_pos); 170+ 171+ fsetpos(fp, &r_pos); 172+ fseek(fp, cur_len, SEEK_CUR); 173+ fgetpos(fp, &r_pos); 174+ } 175+ 176+ fsetpos(fp, &w_pos); 177+ ftruncate(fileno(fp), ftello(fp)); 178+} 179+ 180+static int usage(const char *progname) 181+{ 182+ fprintf(stderr, 183+ "Usage: %s [options] <username>\n" 184+ "\n" 185+ "Options:\n" 186+ " -s read password from stdin\n" 187+ " -a add user\n" 188+ " -x delete user\n", 189+ progname); 190+ return 1; 191+} 192+ 193+int main(int argc, char **argv) 194+{ 195+ const char *prog = argv[0]; 196+ const char *user; 197+ char *pw1, *pw2; 198+ FILE *fp; 199+ bool add = false, delete = false, get_stdin = false, found; 200+ int ch; 201+ int uid; 202+ 203+ TALLOC_CTX *frame = talloc_stackframe(); 204+ 205+ while ((ch = getopt(argc, argv, "asx")) != EOF) { 206+ switch (ch) { 207+ case 's': 208+ get_stdin = true; 209+ break; 210+ case 'a': 211+ add = true; 212+ break; 213+ case 'x': 214+ delete = true; 215+ break; 216+ default: 217+ return usage(prog); 218+ } 219+ } 220+ 221+ if (add && delete) 222+ return usage(prog); 223+ 224+ argc -= optind; 225+ argv += optind; 226+ 227+ if (!argc) 228+ return usage(prog); 229+ 230+ user = argv[0]; 231+ if (!delete) { 232+ uid = find_uid_for_user(user); 233+ if (uid < 0) { 234+ fprintf(stderr, "Could not find user '%s' in /etc/passwd\n", user); 235+ return 2; 236+ } 237+ } 238+ 239+ fp = fopen("/etc/samba/smbpasswd", "r+"); 240+ if(!fp) { 241+ fprintf(stderr, "Failed to open /etc/samba/smbpasswd"); 242+ return 3; 243+ } 244+ 245+ found = find_passwd_line(fp, user, NULL); 246+ if (!add && !found) { 247+ fprintf(stderr, "Could not find user '%s' in /etc/samba/smbpasswd\n", user); 248+ return 3; 249+ } 250+ 251+ if (delete) { 252+ smbpasswd_delete_user(fp); 253+ goto out; 254+ } 255+ 256+ pw1 = get_pass("New SMB password:", get_stdin); 257+ if (!pw1) 258+ pw1 = strdup(""); 259+ 260+ pw2 = get_pass("Retype SMB password:", get_stdin); 261+ if (!pw2) 262+ pw2 = strdup(""); 263+ 264+ if (strcmp(pw1, pw2) != 0) { 265+ fprintf(stderr, "Mismatch - password unchanged.\n"); 266+ goto out_free; 267+ } 268+ 269+ if (found) 270+ fseek(fp, -strlen(buf), SEEK_CUR); 271+ smbpasswd_write_user(fp, user, uid, pw2); 272+ 273+out_free: 274+ free(pw1); 275+ free(pw2); 276+out: 277+ fclose(fp); 278+ TALLOC_FREE(frame); 279+ 280+ return 0; 281+} 282