1/* sane - Scanner Access Now Easy. 2 Copyright (C) 2000 Jochen Eisinger <jochen.eisinger@gmx.net> 3 This file is part of the SANE package. 4 5 This program is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 2 of the 8 License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18 As a special exception, the authors of SANE give permission for 19 additional uses of the libraries contained in this release of SANE. 20 21 The exception is that, if you link a SANE library with other files 22 to produce an executable, this does not by itself cause the 23 resulting executable to be covered by the GNU General Public 24 License. Your use of that executable is in no way restricted on 25 account of linking the SANE library code into it. 26 27 This exception does not, however, invalidate any other reasons why 28 the executable file might be covered by the GNU General Public 29 License. 30 31 If you submit changes to SANE to the maintainers to be included in 32 a subsequent release, you agree by submitting the changes that 33 those changes may be distributed with this exception intact. 34 35 If you write modifications of your own for SANE, it is your choice 36 whether to permit this exception to apply to your modifications. 37 If you do not wish that, delete this exception notice. 38 39 This file implements an interface for user authorization using MD5 digest */ 40 41#include "../include/sane/config.h" 42 43#include <stdlib.h> 44#include <stdio.h> 45 46#include <string.h> 47 48#ifdef HAVE_UNISTD_H 49#include <unistd.h> 50#endif 51 52#include <time.h> 53 54 55#define BACKEND_NAME sanei_auth 56#include "../include/sane/sanei_backend.h" 57#include "../include/sane/sanei_debug.h" 58 59#include "../include/sane/sane.h" 60#include "../include/sane/sanei.h" 61#include "../include/sane/sanei_auth.h" 62#include "../include/sane/sanei_config.h" 63 64#include "../include/md5.h" 65 66static int random_seeded = 0; 67 68#define INIT_RND() do { \ 69 if (random_seeded == 0) { \ 70 random_seeded = 1; \ 71 srand(time(NULL)); \ 72 DBG_INIT(); \ 73 } \ 74 } while (0) 75 76 77#ifdef HAVE_DEV_URANDOM 78 79static unsigned long 80randombits (void) 81{ 82 83 FILE *dev_urandom; 84 unsigned long result = 0; 85 char buffer[4]; 86 87 if ((dev_urandom = fopen ("/dev/urandom", "r")) == NULL) 88 { 89 DBG (2, "randombits: could not open /dev/urandom...\n"); 90 return rand (); 91 } 92 93 fread (buffer, 1, 4, dev_urandom); 94 95 fclose (dev_urandom); 96 97 result = buffer[0]; 98 result <<= 8; 99 result += buffer[1]; 100 result <<= 8; 101 result += buffer[2]; 102 result <<= 8; 103 result += buffer[3]; 104 105 return result; 106 107} 108 109#else 110 111#define randombits rand 112 113#endif 114 115 116static int 117check_passwd (const char *upassword, 118 const char *password, 119 const char *randomstring, const char *username) 120{ 121 122 unsigned char md5digest[16]; 123 char tmpstr[512]; 124 125 if (strncmp (upassword, "$MD5$", 5) == 0) 126 { 127 128 sprintf (tmpstr, "%s%.128s", 129 strstr (randomstring, "$MD5$") + 5, password); 130 md5_buffer (tmpstr, strlen (tmpstr), md5digest); 131 132 sprintf (tmpstr, "$MD5$%02x%02x%02x%02x%02x%02x%02x%02x" 133 "%02x%02x%02x%02x%02x%02x%02x%02x", 134 md5digest[0], md5digest[1], 135 md5digest[2], md5digest[3], 136 md5digest[4], md5digest[5], 137 md5digest[6], md5digest[7], 138 md5digest[8], md5digest[9], 139 md5digest[10], md5digest[11], 140 md5digest[12], md5digest[13], md5digest[14], md5digest[15]); 141 142 143 return (strcmp (upassword, tmpstr) == 0); 144 145 } 146 else 147 { 148 149 DBG (1, "check_passwd: received plain-text reply from user ``%s''\n", 150 username); 151 152 return (strcmp (upassword, password) == 0); 153 154 } 155} 156 157 158SANE_Status 159sanei_authorize (const char *resource, 160 const char *backend, SANE_Auth_Callback authorize) 161{ 162 FILE *passwd_file; 163 char passwd_filename[256]; 164 char line[1024], *linep; 165 SANE_Bool entry_found = SANE_FALSE; 166 char md5resource[256]; 167 char username[SANE_MAX_USERNAME_LEN]; 168 char password[SANE_MAX_PASSWORD_LEN]; 169 170 INIT_RND (); 171 172 DBG (4, "called for ``%s'' by %s\n", resource, backend); 173 174 if (strlen (resource) > 127) 175 DBG (1, "resource is longer than 127 chars...\n"); 176 177 sprintf (passwd_filename, "%s.users", backend); 178 179 passwd_file = sanei_config_open (passwd_filename); 180 181 if (passwd_file == NULL) 182 { 183 DBG (3, "could not open ``%s''...\n", passwd_filename); 184 return SANE_STATUS_GOOD; 185 } 186 187 while (sanei_config_read (line, 1024, passwd_file)) 188 { 189 190 if (strchr (line, ':') != NULL) 191 { 192 if (strchr (strchr (line, ':') + 1, ':') != NULL) 193 { 194 195 if (strcmp (strchr (strchr (line, ':') + 1, ':') + 1, resource) 196 == 0) 197 198 { 199 200 201 202 entry_found = SANE_TRUE; 203 break; 204 205 } 206 } 207 208 } 209 210 } 211 212 if (entry_found == SANE_FALSE) 213 { 214 215 fclose (passwd_file); 216 217 DBG (3, "could not find resource ``%s''...\n", resource); 218 return SANE_STATUS_GOOD; 219 220 } 221 222 if (authorize == NULL) 223 { 224 DBG (2, "no authorization callback supplied by frontend\n"); 225 return SANE_STATUS_ACCESS_DENIED; 226 } 227 228 sprintf (md5resource, "%.128s$MD5$%x%lx%08lx", 229 resource, getpid (), (long int) time (NULL), randombits ()); 230 231 DBG(0, "resource=%s\n", md5resource); 232 233 memset (username, 0, SANE_MAX_USERNAME_LEN); 234 memset (password, 0, SANE_MAX_PASSWORD_LEN); 235 236 (*authorize) (md5resource, username, password); 237 238 239 fseek (passwd_file, 0L, SEEK_SET); 240 241 while (sanei_config_read (line, 1024, passwd_file)) 242 { 243 244 if ((strlen (line) > 0) && (line[strlen (line) - 1] == '\n')) 245 line[strlen (line) - 1] = '\n'; 246 247 if ((strlen (line) > 0) && (line[strlen (line) - 1] == '\r')) 248 line[strlen (line) - 1] = '\r'; 249 250 251 if ((strncmp (line, username, strlen (username)) == 0) && 252 (((strchr (line, ':')) - line) == (signed) strlen (username))) 253 { 254 255 linep = strchr (line, ':') + 1; 256 257 if ((strchr (linep, ':') != NULL) 258 && (strcmp (strchr (linep, ':') + 1, resource) == 0)) 259 { 260 261 *(strchr (linep, ':')) = 0; 262 263 264 if (check_passwd (password, linep, md5resource, username)) 265 { 266 fclose (passwd_file); 267 DBG (2, "authorization succeeded\n"); 268 return SANE_STATUS_GOOD; 269 } 270 } 271 } 272 273 274 } 275 276 fclose (passwd_file); 277 278 DBG (1, "authorization failed\n"); 279 280 return SANE_STATUS_ACCESS_DENIED; 281} 282