* Began (but did not finish) applying GPL3+ declarations to each source file. This...
[citadel.git] / citadel / client_passwords.c
1 /*
2  * $Id$
3  *
4  * Functions which allow the client to remember usernames and passwords for
5  * various sites.
6  *
7  * Copyright (c) 1987-2009 by the citadel.org team
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "sysdep.h"
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <pwd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <libcitadel.h>
35 #include "citadel.h"
36 #include "citadel_ipc.h"
37 #include "commands.h"
38 #include "client_passwords.h"
39
40 #define PWFILENAME "%s/.citadel.passwords"
41
42 void determine_pwfilename(char *pwfile, size_t n) {
43         struct passwd *p;
44
45         p = getpwuid(getuid());
46         if (p == NULL) strcpy(pwfile, "");
47         snprintf(pwfile, n, PWFILENAME, p->pw_dir);
48 }
49
50
51 /*
52  * Check the password file for a host/port match; if found, stuff the user
53  * name and password into the user/pass buffers
54  */
55 void get_stored_password(
56                 char *host,
57                 char *port,
58                 char *username,
59                 char *password) {
60
61         char pwfile[PATH_MAX];
62         FILE *fp;
63         char buf[SIZ];
64         char buf64[SIZ];
65         char hostbuf[256], portbuf[256], ubuf[256], pbuf[256];
66
67         strcpy(username, "");
68         strcpy(password, "");
69
70         determine_pwfilename(pwfile, sizeof pwfile);
71         if (IsEmptyStr(pwfile)) return;
72
73         fp = fopen(pwfile, "r");
74         if (fp == NULL) return;
75         while (fgets(buf64, sizeof buf64, fp) != NULL) {
76                 CtdlDecodeBase64(buf, buf64, sizeof(buf64));
77                 extract_token(hostbuf, buf, 0, '|', sizeof hostbuf);
78                 extract_token(portbuf, buf, 1, '|', sizeof portbuf);
79                 extract_token(ubuf, buf, 2, '|', sizeof ubuf);
80                 extract_token(pbuf, buf, 3, '|', sizeof pbuf);
81
82                 if (!strcasecmp(hostbuf, host)) {
83                         if (!strcasecmp(portbuf, port)) {
84                                 strcpy(username, ubuf);
85                                 strcpy(password, pbuf);
86                         }
87                 }
88         }
89         fclose(fp);
90 }
91
92
93 /*
94  * Set (or clear) stored passwords.
95  */
96 void set_stored_password(
97                 char *host,
98                 char *port,
99                 char *username,
100                 char *password) {
101
102         char pwfile[PATH_MAX];
103         FILE *fp, *oldfp;
104         char buf[SIZ];
105         char buf64[SIZ];
106         char hostbuf[256], portbuf[256], ubuf[256], pbuf[256];
107
108         determine_pwfilename(pwfile, sizeof pwfile);
109         if (IsEmptyStr(pwfile)) return;
110
111         oldfp = fopen(pwfile, "r");
112         if (oldfp == NULL) oldfp = fopen("/dev/null", "r");
113         unlink(pwfile);
114         fp = fopen(pwfile, "w");
115         if (fp == NULL) fp = fopen("/dev/null", "w");
116         while (fgets(buf64, sizeof buf64, oldfp) != NULL) {
117                 CtdlDecodeBase64(buf, buf64, sizeof(buf64));
118                 extract_token(hostbuf, buf, 0, '|', sizeof hostbuf);
119                 extract_token(portbuf, buf, 1, '|', sizeof portbuf);
120                 extract_token(ubuf, buf, 2, '|', sizeof ubuf);
121                 extract_token(pbuf, buf, 3, '|', sizeof pbuf);
122
123                 if ( (strcasecmp(hostbuf, host)) 
124                    || (strcasecmp(portbuf, port)) ) {
125                         snprintf(buf, sizeof buf, "%s|%s|%s|%s|",
126                                 hostbuf, portbuf, ubuf, pbuf);
127                         CtdlEncodeBase64(buf64, buf, strlen(buf), 0);
128                         fprintf(fp, "%s\n", buf64);
129                 }
130         }
131         if (!IsEmptyStr(username)) {
132                 snprintf(buf, sizeof buf, "%s|%s|%s|%s|",
133                         host, port, username, password);
134                 CtdlEncodeBase64(buf64, buf, strlen(buf), 0);
135                 fprintf(fp, "%s\n", buf64);
136         }
137         fclose(oldfp);
138         fclose(fp);
139         chmod(pwfile, 0600);
140 }
141
142
143 /*
144  * Set the password if the user wants to, clear it otherwise 
145  */
146 void offer_to_remember_password(CtdlIPC *ipc,
147                 char *host,
148                 char *port,
149                 char *username,
150                 char *password) {
151
152         if (rc_remember_passwords) {
153                 if (boolprompt("Remember username/password for this site", 0)) {
154                         set_stored_password(host, port, username, password);
155                 }
156                 else {
157                         set_stored_password(host, port, "", "");
158                 }
159         }
160 }