Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/getpass.c
Line
Count
Source
1
/*
2
 *  Unix SMB/CIFS implementation.
3
 *
4
 *  getpass.c - platform independent getpass function.
5
 *
6
 *  Copyright (c) 2010-2012 Andreas Schneider <asn@samba.org>
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 3 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "includes.h"
23
24
#include "system/filesys.h"
25
#include "system/terminal.h"
26
27
#if !defined(SMB_MALLOC)
28
#undef malloc
29
0
#define SMB_MALLOC(s) malloc((s))
30
#endif
31
32
/**
33
 * @internal
34
 *
35
 * @brief Get the password from the console.
36
 *
37
 * @param[in]  prompt   The prompt to display.
38
 *
39
 * @param[in]  buf      The buffer to fill.
40
 *
41
 * @param[in]  len      The length of the buffer.
42
 *
43
 * @param[in]  verify   Should the password be verified?
44
 *
45
 * @return              1 on success, 0 on error.
46
 */
47
static int samba_gets(const char *prompt, char *buf, size_t len, bool verify)
48
0
{
49
0
  char *tmp;
50
0
  char *ptr = NULL;
51
0
  int ok = 0;
52
53
0
  tmp = SMB_MALLOC(len);
54
0
  if (tmp == NULL) {
55
0
    return 0;
56
0
  }
57
0
  memset(tmp,'\0',len);
58
59
  /* read the password */
60
0
  while (!ok) {
61
0
    if (buf[0] != '\0') {
62
0
      fprintf(stdout, "%s[%s] ", prompt, buf);
63
0
    } else {
64
0
      fprintf(stdout, "%s", prompt);
65
0
    }
66
0
    fflush(stdout);
67
0
    if (fgets(tmp, len, stdin) == NULL) {
68
0
      free(tmp);
69
0
      return 0;
70
0
    }
71
72
0
    if ((ptr = strchr(tmp, '\n'))) {
73
0
      *ptr = '\0';
74
0
    }
75
0
    fprintf(stdout, "\n");
76
77
0
    if (*tmp) {
78
0
      strncpy(buf, tmp, len);
79
0
    }
80
81
0
    if (verify) {
82
0
      char *key_string;
83
84
0
      key_string = SMB_MALLOC(len);
85
0
      if (key_string == NULL) {
86
0
        break;
87
0
      }
88
0
      memset(key_string, '\0', len);
89
90
0
      fprintf(stdout, "\nVerifying, please re-enter. %s", prompt);
91
0
      fflush(stdout);
92
0
      if (! fgets(key_string, len, stdin)) {
93
0
        memset(key_string, '\0', len);
94
0
        SAFE_FREE(key_string);
95
0
        clearerr(stdin);
96
0
        continue;
97
0
      }
98
0
      if ((ptr = strchr(key_string, '\n'))) {
99
0
        *ptr = '\0';
100
0
      }
101
0
      fprintf(stdout, "\n");
102
0
      if (strcmp(buf, key_string)) {
103
0
        printf("\n\07\07Mismatch - try again\n");
104
0
        memset(key_string, '\0', len);
105
0
        SAFE_FREE(key_string);
106
0
        fflush(stdout);
107
0
        continue;
108
0
      }
109
0
      memset(key_string, '\0', len);
110
0
      SAFE_FREE(key_string);
111
0
    }
112
0
    ok = 1;
113
0
  }
114
0
  memset(tmp, '\0', len);
115
0
  free(tmp);
116
117
0
  return ok;
118
0
}
119
120
/**
121
 * @brief Get a password from the console.
122
 *
123
 * You should make sure that the buffer is an empty string!
124
 *
125
 * You can also use this function to ask for a username. Then you can fill the
126
 * buffer with the username and it is shows to the users. If the users just
127
 * presses enter the buffer will be untouched.
128
 *
129
 * @code
130
 *   char username[128];
131
 *
132
 *   snprintf(username, sizeof(username), "john");
133
 *
134
 *   samba_getpass("Username:", username, sizeof(username), 1, 0);
135
 * @endcode
136
 *
137
 * The prompt will look like this:
138
 *
139
 *   Username: [john]
140
 *
141
 * If you press enter then john is used as the username, or you can type it in
142
 * to change it.
143
 *
144
 * @param[in]  prompt   The prompt to show to ask for the password.
145
 *
146
 * @param[out] buf    The buffer the password should be stored. It NEEDS to be
147
 *                      empty or filled out.
148
 *
149
 * @param[in]  len      The length of the buffer.
150
 *
151
 * @param[in]  echo     Should we echo what you type.
152
 *
153
 * @param[in]  verify   Should we ask for the password twice.
154
 *
155
 * @return              0 on success, -1 on error.
156
 */
157
int samba_getpass(const char *prompt,
158
      char *buf,
159
      size_t len,
160
      bool echo,
161
      bool verify)
162
0
{
163
0
  struct termios attr;
164
0
  struct termios old_attr;
165
0
  int ok = 0;
166
0
  int fd = -1;
167
168
  /* fgets needs at least len - 1 */
169
0
  if (prompt == NULL || buf == NULL || len < 2) {
170
0
    return -1;
171
0
  }
172
173
0
  if (isatty (STDIN_FILENO)) {
174
175
0
    ZERO_STRUCT(attr);
176
0
    ZERO_STRUCT(old_attr);
177
178
    /* get local terminal attributes */
179
0
    if (tcgetattr(STDIN_FILENO, &attr) < 0) {
180
0
      perror("tcgetattr");
181
0
      return -1;
182
0
    }
183
184
    /* save terminal attributes */
185
0
    memcpy(&old_attr, &attr, sizeof(attr));
186
0
    if((fd = fcntl(0, F_GETFL, 0)) < 0) {
187
0
      perror("fcntl");
188
0
      return -1;
189
0
    }
190
191
    /* disable echo */
192
0
    if (!echo) {
193
0
      attr.c_lflag &= ~(ECHO);
194
0
    }
195
196
    /* write attributes to terminal */
197
0
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) < 0) {
198
0
      perror("tcsetattr");
199
0
      return -1;
200
0
    }
201
0
  }
202
203
  /* disable nonblocking I/O */
204
0
  if (fd & O_NDELAY) {
205
0
    fcntl(0, F_SETFL, fd & ~O_NDELAY);
206
0
  }
207
208
0
  ok = samba_gets(prompt, buf, len, verify);
209
210
0
  if (isatty (STDIN_FILENO)) {
211
212
    /* reset terminal */
213
0
    tcsetattr(STDIN_FILENO, TCSANOW, &old_attr);
214
0
  }
215
216
  /* close fd */
217
0
  if (fd & O_NDELAY) {
218
0
    fcntl(0, F_SETFL, fd);
219
0
  }
220
221
0
  if (!ok) {
222
0
    memset (buf, '\0', len);
223
0
    return -1;
224
0
  }
225
226
  /* force termination */
227
0
  buf[len - 1] = '\0';
228
229
0
  return 0;
230
0
}