1 // Copyright (C) 2010-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 #include <sipwitch-config.h>
18 #include <ucommon/ucommon.h>
19 #include <ucommon/secure.h>
21 #ifdef HAVE_PWD_H
22 #include <pwd.h>
23 #endif
24
25 using namespace sipwitch;
26
27 #ifdef _MSWINDOWS_
28 #include <io.h>
29 static char *getpass(const char *prompt)
30 {
31 static char buf[128];
32 size_t i;
33
34 fputs(prompt, stderr);
35 fflush(stderr);
36 for (i = 0; i < sizeof(buf) - 1; i++) {
37 buf[i] = fgetc(stdin);
38 if (buf[i] == '\r' || buf[i] == '\n')
39 break;
40 fputs("*", stderr);
41 fflush(stderr);
42 }
43 buf[i] = 0;
44 fputs("\n", stderr);
45 fflush(stderr);
46 return buf;
47 }
48 #endif
49
51 {
52 const char *realm = NULL, *secret, *verify;
53 const char *mode = "md5";
54 char buffer[128];
55 char replace[128];
56 string_t digestbuf;
57 fpos_t pos;
58 FILE *fp;
59
60 #ifdef _MSWINDOWS_
61 const char *
control =
"\\\\.\\mailslot\\sipwitch_ctrl";
62 #else
63 const char *control = DEFAULT_VARPATH "/run/sipwitch/control";
64 #endif
65
66 const char *user = *(++argv);
67
68 if(String::equal(user, "-version")) {
69 printf("sippasswd 0.1\n"
70 "Copyright (C) 2010 David Sugar, Tycho Softworks\n"
71 "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
72 "This is free software: you are free to change and redistribute it.\n"
73 "There is NO WARRANTY, to the extent permitted by law.\n");
74 exit(0);
75 }
76
77 #ifdef HAVE_PWD_H
78 if(user && getuid() != 0)
79 shell::errexit(3, "*** sippasswd: only root can change other user's digests\n");
80
81 if(!user) {
82 struct passwd *pwd = getpwuid(getuid());
83 if(!pwd)
84 shell::errexit(3, "*** sippasswd: user id cannot be determined\n");
85
86 user = strdup(pwd->pw_name);
87 }
88 if(geteuid() != 0)
89 shell::errexit(3, "*** sippasswd: root privilege required\n");
90 #else
91 if(!user)
92 shell::errexit(3, "*** sippasswd: user id not specified\n");
93
94 #endif
95
96 fsys_t fs;
97 fs.open(DEFAULT_CFGPATH "/siprealm", fsys::RDONLY);
98
99 if(!is(fs))
100 fs.open(DEFAULT_VARPATH "/lib/sipwitch/uuid", fsys::RDONLY);
101
102 if(!is(fs))
103 shell::errexit(4, "*** sippasswd: no realm active\n");
104
105 memset(buffer, 0, sizeof(buffer));
106 fs.read(buffer, sizeof(buffer) - 1);
107 fs.close();
108
109 char *cp = strchr(buffer, '\n');
110 if(cp)
111 *cp = 0;
112
113 cp = strchr(buffer, ':');
114 if(cp)
115 *(cp++) = 0;
116
117 if(cp && *cp)
118 mode = cp;
119
120 realm = strdup(buffer);
121 secret = getpass("Enter new SIP secret: ");
122 if(!secret || !*secret) {
123 printf("no password supplied\n");
124 exit(0);
125 }
126
127 verify = getpass("Retype new SIP secret: ");
128 if(!verify || !*verify || !String::equal(secret, verify)) {
129 printf("sorry, secrets do not match\n");
130 exit(0);
131 }
132
133 digest_t digest(mode);
134
135 if(!digest.puts((string_t)user + ":" + (string_t)realm + ":" + (string_t)secret))
136 shell::errexit(1, "*** sippasswd: cannot compute");
137 else
138 digestbuf = *digest;
139
140 snprintf(replace, sizeof(replace), "%s:%s\n", user, *digestbuf);
141
142 // create work directory if it does not exist
143 dir::create(DEFAULT_VARPATH "/lib/sipwitch", fsys::GROUP_PRIVATE);
144 dir::create(DEFAULT_VARPATH "/lib/sipwitch/digests", fsys::GROUP_PRIVATE);
145
146 // make sure always created root only
147 string_t path = str(DEFAULT_VARPATH "/lib/sipwitch/digests/") + realm;
148 fs.open(*path, fsys::OWNER_PRIVATE, fsys::RDONLY);
149 fs.close();
150
151 fp = fopen(*path, "r+");
152 if(!fp)
153 shell::errexit(1, "*** sippasswd: cannot access digest");
154
155 for(;;) {
156 fgetpos(fp, &pos);
157 if(NULL == fgets(buffer, sizeof(buffer), fp) || feof(fp))
158 break;
159
160 if(String::equal(buffer, replace)) {
161 fclose(fp);
162 printf("digest unchanged\n");
163 exit(0);
164 }
165
166 cp = strchr(buffer, ':');
167 if(!cp)
168 continue;
169
170 *cp = 0;
171 if(String::equal(buffer, user))
172 break;
173 }
174
175 // update digest file
176 fsetpos(fp, &pos);
177 fputs(replace, fp);
178 fclose(fp);
179
180 // if server is up, also sync server with digest change...
181 fp = fopen(control, "w");
182 if(fp) {
183 fprintf(fp, "digest %s %s\n", user, *digestbuf);
184 fclose(fp);
185 }
186
187 printf("digest updated\n");
188 PROGRAM_EXIT(0);
189 }
190
Server control interfaces and functions.
Top level include directory for GNU Telephony SIP Witch Server.