basic_ncsa_auth.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/*
10 * AUTHOR: Arjan de Vet <Arjan.deVet@adv.iae.nl>
11 *
12 * Example authentication program for Squid, based on the original
13 * proxy_auth code from client_side.c, written by
14 * Jon Thackray <jrmt@uk.gdscorp.com>.
15 *
16 * Uses a NCSA httpd style password file for authentication with the
17 * following improvements suggested by various people:
18 *
19 * - comment lines are possible and should start with a '#';
20 * - empty or blank lines are possible;
21 * - extra fields in the password file are ignored; this makes it
22 * possible to use a Unix password file but I do not recommend that.
23 *
24 * MD5 without salt and magic strings - Added by Ramon de Carvalho and Rodrigo Rubira Branco
25 */
26
27#include "squid.h"
30#include "rfc1738.h"
31
32#include <string>
33#include <unordered_map>
34#if HAVE_SYS_STAT_H
35#include <sys/stat.h>
36#endif
37#if HAVE_CRYPT_H
38#include <crypt.h>
39#endif
40
41typedef std::unordered_map<std::string, std::string> usermap_t;
43
44static void
46{
47 FILE *f;
48 char buf[HELPER_INPUT_BUFFER];
49 char *user;
50 char *passwd;
51
52 usermap.clear();
53 //TODO: change to c++ streams
54 f = fopen(passwdfile, "r");
55 if (!f) {
56 int xerrno = errno;
57 fprintf(stderr, "FATAL: %s: %s\n", passwdfile, xstrerr(xerrno));
58 exit(EXIT_FAILURE);
59 }
60 unsigned int lineCount = 0;
61 buf[HELPER_INPUT_BUFFER-1] = '\0';
62 while (fgets(buf, sizeof(buf)-1, f) != nullptr) {
63 ++lineCount;
64 if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') ||
65 (buf[0] == '\n'))
66 continue;
67 user = strtok(buf, ":\n\r");
68 if (user == nullptr) {
69 fprintf(stderr, "ERROR: Missing user name at %s line %d\n", passwdfile, lineCount);
70 continue;
71 }
72 passwd = strtok(nullptr, ":\n\r");
73 if ((strlen(user) > 0) && passwd) {
74 usermap[user] = passwd;
75 }
76 }
77 fclose(f);
78}
79
80int
81main(int argc, char **argv)
82{
83 struct stat sb;
84 time_t change_time = -1;
85 char buf[HELPER_INPUT_BUFFER];
86 char *user, *passwd, *p;
87 setbuf(stdout, nullptr);
88 if (argc != 2) {
89 fprintf(stderr, "Usage: ncsa_auth <passwordfile>\n");
90 exit(EXIT_FAILURE);
91 }
92 if (stat(argv[1], &sb) != 0) {
93 fprintf(stderr, "FATAL: cannot stat %s\n", argv[1]);
94 exit(EXIT_FAILURE);
95 }
96 while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != nullptr) {
97 if ((p = strchr(buf, '\n')) != nullptr)
98 *p = '\0'; /* strip \n */
99 if (stat(argv[1], &sb) == 0) {
100 if (sb.st_mtime != change_time) {
101 read_passwd_file(argv[1]);
102 change_time = sb.st_mtime;
103 }
104 }
105 if ((user = strtok(buf, " ")) == nullptr) {
106 SEND_ERR("");
107 continue;
108 }
109 if ((passwd = strtok(nullptr, "")) == nullptr) {
110 SEND_ERR("");
111 continue;
112 }
113 rfc1738_unescape(user);
114 rfc1738_unescape(passwd);
115 const auto userpassIterator = usermap.find(user);
116 if (userpassIterator == usermap.end()) {
117 SEND_ERR("No such user");
118 continue;
119 }
120 std::string stored_pass = userpassIterator->second;
121 const char *salted = stored_pass.c_str(); // locally stored version contains salt etc.
122
123 char *crypted = nullptr;
124#if HAVE_CRYPT
125 size_t passwordLength = strlen(passwd);
126 // Bug 3831: given algorithms more secure than DES crypt() does not truncate, so we can ignore the bug 3107 length checks below
127 // '$1$' = MD5, '$2a$' = Blowfish, '$5$' = SHA256 (Linux), '$6$' = SHA256 (BSD) and SHA512
128 if (passwordLength > 1 && salted[0] == '$' &&
129 (crypted = crypt(passwd, salted)) && stored_pass == crypted) {
130 SEND_OK("");
131 continue;
132 }
133 // 'other' prefixes indicate DES algorithm.
134 if (passwordLength <= 8 && (crypted = crypt(passwd, salted)) && stored_pass == crypted) {
135 SEND_OK("");
136 continue;
137 }
138 if (passwordLength > 8 && (crypted = crypt(passwd, salted)) && stored_pass == crypted) {
139 // Bug 3107: crypt() DES functionality silently truncates long passwords.
140 SEND_ERR("Password too long. Only 8 characters accepted.");
141 continue;
142 }
143
144#endif
145 if ( (crypted = crypt_md5(passwd, salted)) && stored_pass == crypted) {
146 SEND_OK("");
147 continue;
148 }
149 if ( (crypted = md5sum(passwd)) && stored_pass == crypted) {
150 SEND_OK("");
151 continue;
152 }
153 SEND_ERR("Wrong password");
154 }
155 return EXIT_SUCCESS;
156}
157
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:24
usermap_t usermap
int main(int argc, char **argv)
static void read_passwd_file(const char *passwdfile)
std::unordered_map< std::string, std::string > usermap_t
char * md5sum(const char *s)
Definition: crypt_md5.cc:183
char * crypt_md5(const char *pw, const char *salt)
Definition: crypt_md5.cc:54
char * crypt(const char *wort, const char *salt)
Definition: encrypt.c:240
#define SEND_ERR(x)
#define SEND_OK(x)
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
static struct stat sb
Definition: squidclient.cc:71
static char * passwdfile
Definition: text_backend.cc:43
static time_t change_time
Definition: text_backend.cc:45
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors